GCC Code Coverage Report


Directory: ./
File: storage/rocksdb/ha_rocksdb.cc
Date: 2022-11-26 14:12:44
Exec Total Coverage
Lines: 5538 6227 88.9%
Branches: 5376 10837 49.6%

Line Branch Exec Source
1 /*
2 Copyright (c) 2012, Monty Program Ab
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
17 #ifdef USE_PRAGMA_IMPLEMENTATION
18 #pragma implementation // gcc: Class implementation
19 #endif
20
21 #define MYSQL_SERVER 1
22
23 /* The C++ file's header */
24 #include "./ha_rocksdb.h"
25
26 #ifdef TARGET_OS_LINUX
27 #include <errno.h>
28 #include <sys/resource.h>
29 #include <sys/syscall.h>
30 #include <sys/types.h>
31 #endif
32
33 /* C++ standard header files */
34 #include <inttypes.h>
35 #include <algorithm>
36 #include <deque>
37 #include <limits>
38 #include <map>
39 #include <queue>
40 #include <set>
41 #include <string>
42 #include <vector>
43
44 /* MySQL includes */
45 #include "my_bit.h"
46 #include "my_stacktrace.h"
47 #include "my_sys.h"
48 #include "mysql/thread_pool_priv.h"
49 #include "mysys_err.h"
50 #include "scope_guard.h"
51 #include "sql/debug_sync.h"
52 #include "sql-common/json_dom.h"
53 #include "sql/mysqld.h"
54 #include "sql/sql_audit.h"
55 #include "sql/sql_lex.h"
56 #include "sql/sql_partition.h"
57 #include "sql/sql_table.h"
58 #include "sql/sql_thd_internal_api.h"
59 #include "sql/table.h"
60
61 /* RocksDB includes */
62 #include "monitoring/histogram.h"
63 #include "rocksdb/compaction_filter.h"
64 #include "rocksdb/compaction_job_stats.h"
65 #include "rocksdb/env.h"
66 #include "rocksdb/env/composite_env_wrapper.h"
67 #include "rocksdb/memory_allocator.h"
68 #include "rocksdb/persistent_cache.h"
69 #include "rocksdb/rate_limiter.h"
70 #include "rocksdb/slice_transform.h"
71 #include "rocksdb/thread_status.h"
72 #include "rocksdb/trace_reader_writer.h"
73 #include "rocksdb/utilities/checkpoint.h"
74 #include "rocksdb/utilities/convenience.h"
75 #include "rocksdb/utilities/fault_injection_fs.h"
76 #include "rocksdb/utilities/memory_util.h"
77 #include "rocksdb/utilities/sim_cache.h"
78 #include "rocksdb/utilities/write_batch_with_index.h"
79 #include "util/stop_watch.h"
80
81 /* MyRocks includes */
82 #include "./event_listener.h"
83 #include "./ha_rocksdb_proto.h"
84 #include "./ha_rockspart.h"
85 #include "./logger.h"
86 #include "./rdb_cf_manager.h"
87 #include "./rdb_cf_options.h"
88 #include "./rdb_converter.h"
89 #include "./rdb_datadic.h"
90 #include "./rdb_i_s.h"
91 #include "./rdb_index_merge.h"
92 #include "./rdb_iterator.h"
93 #include "./rdb_mutex_wrapper.h"
94 #include "./rdb_psi.h"
95 #include "./rdb_threads.h"
96
97 #ifdef RAPIDJSON_NO_SIZETYPEDEFINE
98 // if we build within the server, it will set RAPIDJSON_NO_SIZETYPEDEFINE
99 // globally and require to include my_rapidjson_size_t.h
100 #include "my_rapidjson_size_t.h"
101 #endif
102 #include <rapidjson/document.h>
103
104 #ifdef FB_HAVE_WSENV
105 #include "./ObjectFactory.h"
106 #endif
107
108 // MySQL 8.0 logger service interface
109 static SERVICE_TYPE(registry) *reg_srv = nullptr;
110 SERVICE_TYPE(log_builtins) *log_bi = nullptr;
111 SERVICE_TYPE(log_builtins_string) *log_bs = nullptr;
112
113 namespace myrocks {
114
115 static st_global_stats global_stats;
116 static st_export_stats export_stats;
117 static st_memory_stats memory_stats;
118 static st_io_stall_stats io_stall_stats;
119 Rdb_compaction_stats compaction_stats;
120
121 const std::string DEFAULT_CF_NAME("default");
122 const std::string DEFAULT_SYSTEM_CF_NAME("__system__");
123 const std::string DEFAULT_TMP_CF_NAME("__tmp__");
124 const std::string DEFAULT_TMP_SYSTEM_CF_NAME("__tmp_system__");
125 const std::string PER_INDEX_CF_NAME("$per_index_cf");
126 const std::string DEFAULT_SK_CF_NAME("default_sk");
127 const std::string TRUNCATE_TABLE_PREFIX("#truncate_tmp#");
128 const std::string TMP_SCHEMA_NAME("#sqltmp");
129
130 static std::vector<std::string> rdb_tables_to_recalc;
131
132 static Rdb_exec_time st_rdb_exec_time;
133
134 int mysql_value_to_bool(struct st_mysql_value *value, bool *return_value);
135
136 /**
137 Updates row counters based on the table type and operation type.
138 */
139 257309685 void ha_rocksdb::update_row_stats(const operation_type &type, ulonglong count) {
140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 257309685 times.
257309685 assert(type < ROWS_MAX);
141 // Find if we are modifying system databases.
142
3/4
✓ Branch 0 taken 257321022 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 257321004 times.
257309685 if (table->s && m_tbl_def->m_is_mysql_system_table) {
143 18 global_stats.system_rows[type].add(count);
144 } else {
145 257309667 global_stats.rows[type].add(count);
146 }
147 257351031 }
148
149 void ha_rocksdb::update_row_read(ulonglong count) {
150 update_row_stats(ROWS_READ, count);
151 }
152
153 40349069 void ha_rocksdb::inc_covered_sk_lookup() {
154 40349069 global_stats.covered_secondary_key_lookups.inc();
155 40349069 }
156
157 void dbug_dump_database(rocksdb::DB *db);
158 static handler *rocksdb_create_handler(my_core::handlerton *hton,
159 my_core::TABLE_SHARE *table_arg,
160 bool partitioned,
161 my_core::MEM_ROOT *mem_root);
162
163 27839 static rocksdb::CompactRangeOptions getCompactRangeOptions(
164 int concurrency = 0,
165 rocksdb::BottommostLevelCompaction bottommost_level_compaction =
166 rocksdb::BottommostLevelCompaction::kForceOptimized) {
167 27839 rocksdb::CompactRangeOptions compact_range_options;
168 27839 compact_range_options.bottommost_level_compaction =
169 bottommost_level_compaction;
170 27839 compact_range_options.exclusive_manual_compaction = false;
171
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 27827 times.
27839 if (concurrency > 0) {
172 12 compact_range_options.max_subcompactions = concurrency;
173 }
174 27839 return compact_range_options;
175 }
176
177 ///////////////////////////////////////////////////////////
178 // Parameters and settings
179 ///////////////////////////////////////////////////////////
180 static char *rocksdb_default_cf_options = nullptr;
181 static char *rocksdb_override_cf_options = nullptr;
182 static char *rocksdb_update_cf_options = nullptr;
183 static bool rocksdb_use_default_sk_cf = false;
184 static bool rocksdb_allow_unsafe_alter = false;
185
186 ///////////////////////////////////////////////////////////
187 // Globals
188 ///////////////////////////////////////////////////////////
189 handlerton *rocksdb_hton;
190
191 rocksdb::TransactionDB *rdb = nullptr;
192 rocksdb::HistogramImpl *commit_latency_stats = nullptr;
193
194 static std::shared_ptr<rocksdb::Statistics> rocksdb_stats;
195 static std::shared_ptr<Rdb_tbl_prop_coll_factory> properties_collector_factory;
196
197 Rdb_dict_manager_selector dict_manager;
198 Rdb_cf_manager cf_manager;
199 Rdb_ddl_manager ddl_manager;
200 Rdb_hton_init_state hton_init_state;
201
202 /**
203 MyRocks background thread control
204 N.B. This is besides RocksDB's own background threads
205 (@see rocksdb::CancelAllBackgroundWork())
206 */
207
208 static Rdb_background_thread rdb_bg_thread;
209
210 static Rdb_index_stats_thread rdb_is_thread;
211
212 static Rdb_manual_compaction_thread rdb_mc_thread;
213
214 static Rdb_drop_index_thread rdb_drop_idx_thread;
215 // List of table names (using regex) that are exceptions to the strict
216 // collation check requirement.
217 Regex_list_handler *rdb_collation_exceptions;
218
219 static const char *rdb_get_error_messages(int error);
220
221 1973 static void rocksdb_flush_all_memtables() {
222 1973 const Rdb_cf_manager &cf_manager = rdb_get_cf_manager();
223
224
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 1940 times.
1973 if (!cf_manager.is_initialized()) return;
225
226 // RocksDB will fail the flush if the CF is deleted,
227 // but here we don't handle return status
228
3/4
✓ Branch 0 taken 1940 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7543 times.
✓ Branch 3 taken 1940 times.
9483 for (const auto &cf_handle : cf_manager.get_all_cf()) {
229
1/2
✓ Branch 0 taken 7543 times.
✗ Branch 1 not taken.
7543 rdb->Flush(rocksdb::FlushOptions(), cf_handle.get());
230 1940 }
231 }
232
233 39 static void rocksdb_delete_column_family_stub(THD *const /* thd */,
234 struct SYS_VAR *const /* var */,
235 void *const /* var_ptr */,
236 39 const void *const /* save */) {}
237
238 55 static int rocksdb_delete_column_family(THD *const /* thd */,
239 struct SYS_VAR *const /* var */,
240 void *const /* var_ptr */,
241 struct st_mysql_value *const value) {
242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 assert(value != nullptr);
243
244 char buff[STRING_BUFFER_USUAL_SIZE];
245 55 int len = sizeof(buff);
246
247
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 const char *const cf = value->val_str(value, buff, &len);
248
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 54 times.
55 if (cf == nullptr) return HA_EXIT_SUCCESS;
249
250
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 std::string cf_name = std::string(cf);
251 // Forbid to remove these built-in CFs
252
4/4
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 1 times.
159 if (cf_name == DEFAULT_SYSTEM_CF_NAME || cf_name == DEFAULT_CF_NAME ||
253
6/6
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 48 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 48 times.
162 cf_name.empty() ||
254
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
54 (cf_name == DEFAULT_SK_CF_NAME && rocksdb_use_default_sk_cf)) {
255
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 my_error(ER_CANT_DROP_CF, MYF(0), cf);
256 6 return HA_EXIT_FAILURE;
257 }
258
259
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 auto &cf_manager = rdb_get_cf_manager();
260 48 int ret = 0;
261
262 {
263
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 auto local_dict_manager = dict_manager.get_dict_manager_selector_non_const(
264 false /*is_tmp_table*/);
265
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 std::lock_guard<Rdb_dict_manager> dm_lock(*local_dict_manager);
266
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 ret = cf_manager.drop_cf(&ddl_manager, local_dict_manager, cf_name);
267 48 }
268
269
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 10 times.
48 if (ret == HA_EXIT_SUCCESS) {
270
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 rdb_drop_idx_thread.signal();
271 } else {
272
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 my_error(ER_CANT_DROP_CF, MYF(0), cf);
273 }
274
275 48 return ret;
276 54 }
277
278 ///////////////////////////////////////////////////////////
279 // Hash map: table name => open table handler
280 ///////////////////////////////////////////////////////////
281
282 namespace // anonymous namespace = not visible outside this source file
283 {
284
285 class Rdb_open_tables_map {
286 private:
287 /* Hash table used to track the handlers of open tables */
288 std::unordered_map<std::string, Rdb_table_handler *> m_table_map;
289
290 /* The mutex used to protect the hash table */
291 mutable Rds_mysql_mutex m_mutex;
292
293 public:
294 932 void init() {
295 932 m_table_map.clear();
296 932 m_mutex.init(rdb_psi_open_tbls_mutex_key, MY_MUTEX_INIT_FAST);
297 932 }
298
299 929 void free() {
300 929 m_table_map.clear();
301 929 m_mutex.destroy();
302 929 }
303
304 899 size_t count() { return m_table_map.size(); }
305
306 Rdb_table_handler *get_table_handler(const char *const table_name);
307 void release_table_handler(Rdb_table_handler *const table_handler);
308
309 std::vector<std::string> get_table_names(void) const;
310 };
311
312 } // anonymous namespace
313
314 static Rdb_open_tables_map rdb_open_tables;
315
316 10 static std::string rdb_normalize_dir(std::string dir) {
317
6/6
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 10 times.
12 while (dir.size() > 0 && dir.back() == '/') {
318 2 dir.resize(dir.size() - 1);
319 }
320 10 return dir;
321 }
322
323 7 static int rocksdb_create_checkpoint(const char *checkpoint_dir_raw) {
324
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(checkpoint_dir_raw);
325
326
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
14 const auto checkpoint_dir = rdb_normalize_dir(checkpoint_dir_raw);
327
9/18
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 7 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 7 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 7 times.
✗ Branch 17 not taken.
7 LogPluginErrMsg(INFORMATION_LEVEL, 0,
328 "creating checkpoint in directory: %s\n",
329 checkpoint_dir.c_str());
330 rocksdb::Checkpoint *checkpoint;
331
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 auto status = rocksdb::Checkpoint::Create(rdb, &checkpoint);
332
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 if (status.ok()) {
333
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 status = checkpoint->CreateCheckpoint(checkpoint_dir.c_str());
334
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 delete checkpoint;
335
3/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 2 times.
7 if (status.ok()) {
336
9/18
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 5 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 5 times.
✗ Branch 17 not taken.
5 LogPluginErrMsg(INFORMATION_LEVEL, 0,
337 "created checkpoint in directory: %s\n",
338 checkpoint_dir.c_str());
339 5 return HA_EXIT_SUCCESS;
340 } else {
341
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 my_error(ER_GET_ERRMSG, MYF(0), status.code(), status.ToString().c_str(),
342 rocksdb_hton_name);
343 }
344 } else {
345 my_error(ER_GET_ERRMSG, MYF(0), status.code(), status.ToString().c_str(),
346 rocksdb_hton_name);
347 }
348
349 2 return HA_EXIT_FAILURE;
350 7 }
351
352 3 static int rocksdb_remove_checkpoint(const char *checkpoint_dir_raw) {
353
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 const auto checkpoint_dir = rdb_normalize_dir(checkpoint_dir_raw);
354
9/18
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LogPluginErrMsg(INFORMATION_LEVEL, 0,
355 "deleting temporary checkpoint in directory : %s\n",
356 checkpoint_dir.c_str());
357
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 const auto status = rocksdb::DestroyDB(checkpoint_dir, rocksdb::Options());
358
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 if (status.ok()) {
359 3 return HA_EXIT_SUCCESS;
360 }
361 my_error(ER_GET_ERRMSG, MYF(0), status.code(), status.ToString().c_str(),
362 rocksdb_hton_name);
363 return HA_EXIT_FAILURE;
364 3 }
365
366 3 static int rocksdb_create_checkpoint_validate(
367 THD *const thd MY_ATTRIBUTE((__unused__)),
368 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
369 void *const save MY_ATTRIBUTE((__unused__)),
370 struct st_mysql_value *const value) {
371 char buf[FN_REFLEN];
372 3 int len = sizeof(buf);
373
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 const char *const checkpoint_dir_raw = value->val_str(value, buf, &len);
374
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (checkpoint_dir_raw) {
375
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 return rocksdb_create_checkpoint(checkpoint_dir_raw);
376 }
377 return HA_EXIT_FAILURE;
378 }
379
380 /* This method is needed to indicate that the
381 ROCKSDB_CREATE_CHECKPOINT command is not read-only */
382 4 static void rocksdb_create_checkpoint_update(THD *const thd,
383 struct SYS_VAR *const var,
384 void *const var_ptr,
385 4 const void *const save) {}
386
387 static int rocksdb_create_temporary_checkpoint_validate(
388 THD *const thd, struct SYS_VAR *const var, void *const save,
389 struct st_mysql_value *const value);
390
391 static void rocksdb_disable_file_deletions_update(
392 my_core::THD *const thd, my_core::SYS_VAR *const /* unused */,
393 void *const var_ptr, const void *const save);
394
395 static void rocksdb_max_compaction_history_update(
396 my_core::THD *const thd, my_core::SYS_VAR *const /* unused */,
397 void *const var_ptr, const void *const save);
398
399 static bool parse_fault_injection_params(bool *retryable,
400 uint32_t *failure_ratio,
401 std::vector<rocksdb::FileType> *types);
402
403 1070 static void rocksdb_force_flush_memtable_now_stub(
404 THD *const thd MY_ATTRIBUTE((__unused__)),
405 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
406 void *const var_ptr MY_ATTRIBUTE((__unused__)),
407 1070 const void *const save MY_ATTRIBUTE((__unused__))) {}
408
409 1070 static int rocksdb_force_flush_memtable_now(
410 THD *const thd, struct SYS_VAR *const var, void *const var_ptr,
411 struct st_mysql_value *const value) {
412 1070 bool parsed_value = false;
413
6/8
✓ Branch 0 taken 1070 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1070 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1067 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 1067 times.
1070 if (mysql_value_to_bool(value, &parsed_value) != 0 || !parsed_value) {
414 3 return 1;
415 }
416
417
9/18
✓ Branch 0 taken 1067 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1067 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1067 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1067 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1067 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1067 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1067 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1067 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1067 times.
✗ Branch 17 not taken.
1067 LogPluginErrMsg(INFORMATION_LEVEL, 0, "Manual memtable flush.");
418
1/2
✓ Branch 0 taken 1067 times.
✗ Branch 1 not taken.
1067 rocksdb_flush_all_memtables();
419 1067 return HA_EXIT_SUCCESS;
420 }
421
422 10 static void rocksdb_force_flush_memtable_and_lzero_now_stub(
423 THD *const thd, struct SYS_VAR *const var, void *const var_ptr,
424 10 const void *const save) {}
425
426 7 static int rocksdb_force_flush_memtable_and_lzero_now(
427 THD *const thd, struct SYS_VAR *const var, void *const var_ptr,
428 struct st_mysql_value *const value) {
429
9/18
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 7 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 7 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 7 times.
✗ Branch 17 not taken.
7 LogPluginErrMsg(INFORMATION_LEVEL, 0, "Manual memtable and L0 flush.");
430
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 rocksdb_flush_all_memtables();
431
432
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 const Rdb_cf_manager &cf_manager = rdb_get_cf_manager();
433 7 rocksdb::CompactionOptions c_options = rocksdb::CompactionOptions();
434
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 rocksdb::ColumnFamilyMetaData metadata;
435
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 rocksdb::ColumnFamilyDescriptor cf_descr;
436
437 static constexpr int max_attempts = 3;
438 7 int i, num_errors = 0;
439
440
3/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 7 times.
39 for (const auto &cf_handle : cf_manager.get_all_cf()) {
441
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 for (i = 0; i < max_attempts; i++) {
442
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 rdb->GetColumnFamilyMetaData(cf_handle.get(), &metadata);
443
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 cf_handle->GetDescriptor(&cf_descr);
444 36 c_options.output_file_size_limit = cf_descr.options.target_file_size_base;
445
446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 assert(metadata.levels[0].level == 0);
447 36 std::vector<std::string> file_names;
448
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 36 times.
54 for (const auto &file : metadata.levels[0].files) {
449
2/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 file_names.emplace_back(file.db_path + file.name);
450 }
451
452
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 7 times.
36 if (file_names.empty()) {
453 29 break;
454 }
455
456 7 rocksdb::Status s;
457
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 s = rdb->CompactFiles(c_options, cf_handle.get(), file_names, 1);
458
459
3/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 4 times.
7 if (!s.ok()) {
460 std::shared_ptr<rocksdb::ColumnFamilyHandle> cfh =
461
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 cf_manager.get_cf(cf_handle->GetID());
462
463 // If the CF handle has been removed from cf_manager, it is not an
464 // error. We are done with this CF and proceed to the next CF.
465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!cfh) {
466 LogPluginErrMsg(INFORMATION_LEVEL, 0,
467 "cf %s has been dropped during CompactFiles.",
468 cf_handle->GetName().c_str());
469 break;
470 }
471
472 // Due to a race, it's possible for CompactFiles to collide
473 // with auto compaction, causing an error to return
474 // regarding file not found. In that case, retry.
475
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (s.IsInvalidArgument()) {
476 continue;
477 }
478
479
5/10
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
3 if (!s.ok() && !s.IsAborted()) {
480 rdb_handle_io_error(s, RDB_IO_ERROR_GENERAL);
481 return HA_EXIT_FAILURE;
482 }
483 3 break;
484
1/3
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
3 }
485
4/8
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
39 }
486
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if (i == max_attempts) {
487 num_errors++;
488 }
489
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 }
490
491 7 return num_errors == 0 ? HA_EXIT_SUCCESS : HA_EXIT_FAILURE;
492 7 }
493
494 16 static void rocksdb_cancel_manual_compactions_stub(
495 THD *const thd MY_ATTRIBUTE((__unused__)),
496 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
497 void *const var_ptr MY_ATTRIBUTE((__unused__)),
498 16 const void *const save MY_ATTRIBUTE((__unused__))) {}
499
500 13 static int rocksdb_cancel_manual_compactions(
501 THD *const thd MY_ATTRIBUTE((__unused__)),
502 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
503 void *const var_ptr MY_ATTRIBUTE((__unused__)),
504 struct st_mysql_value *const value MY_ATTRIBUTE((__unused__))) {
505 13 rdb_mc_thread.cancel_all_pending_manual_compaction_requests();
506 // NO_LINT_DEBUG
507
8/16
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 13 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 13 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 13 times.
✗ Branch 15 not taken.
13 LogPluginErrMsg(INFORMATION_LEVEL, 0,
508 "RocksDB: Stopping all Manual Compactions.");
509 13 rdb->GetBaseDB()->DisableManualCompaction();
510 // NO_LINT_DEBUG
511
8/16
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 13 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 13 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 13 times.
✗ Branch 15 not taken.
13 LogPluginErrMsg(INFORMATION_LEVEL, 0,
512 "RocksDB: Enabling Manual Compactions.");
513 13 rdb->GetBaseDB()->EnableManualCompaction();
514 13 return HA_EXIT_SUCCESS;
515 }
516
517 static void rocksdb_drop_index_wakeup_thread(
518 my_core::THD *const thd MY_ATTRIBUTE((__unused__)),
519 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
520 void *const var_ptr MY_ATTRIBUTE((__unused__)), const void *const save);
521
522 static bool rocksdb_pause_background_work = false;
523 static Rds_mysql_mutex rdb_sysvars_mutex;
524 static Rds_mysql_mutex rdb_block_cache_resize_mutex;
525 static Rds_mysql_mutex rdb_bottom_pri_background_compactions_resize_mutex;
526
527 106 static void rocksdb_set_pause_background_work(
528 my_core::THD *const thd MY_ATTRIBUTE((__unused__)),
529 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
530 void *const var_ptr MY_ATTRIBUTE((__unused__)), const void *const save) {
531 106 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
532 106 const bool pause_requested = *static_cast<const bool *>(save);
533
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 14 times.
106 if (rocksdb_pause_background_work != pause_requested) {
534
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 46 times.
92 if (pause_requested) {
535 46 rdb->PauseBackgroundWork();
536 } else {
537 46 rdb->ContinueBackgroundWork();
538 }
539 92 rocksdb_pause_background_work = pause_requested;
540 }
541 106 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
542 106 }
543
544 static void rocksdb_set_compaction_options(THD *thd, struct SYS_VAR *var,
545 void *var_ptr, const void *save);
546
547 static void rocksdb_set_table_stats_sampling_pct(THD *thd, struct SYS_VAR *var,
548 void *var_ptr,
549 const void *save);
550
551 static void rocksdb_update_table_stats_use_table_scan(
552 THD *const /* thd */, struct SYS_VAR *const /* var */, void *const var_ptr,
553 const void *const save);
554
555 static int rocksdb_index_stats_thread_renice(
556 THD *const /* thd */, struct SYS_VAR *const /* var */, void *const save,
557 struct st_mysql_value *const value);
558
559 static void rocksdb_set_rate_limiter_bytes_per_sec(THD *thd,
560 struct SYS_VAR *var,
561 void *var_ptr,
562 const void *save);
563
564 static void rocksdb_set_sst_mgr_rate_bytes_per_sec(THD *thd,
565 struct SYS_VAR *var,
566 void *var_ptr,
567 const void *save);
568
569 static void rocksdb_set_delayed_write_rate(THD *thd, struct SYS_VAR *var,
570 void *var_ptr, const void *save);
571
572 static void rocksdb_set_max_latest_deadlocks(THD *thd, struct SYS_VAR *var,
573 void *var_ptr, const void *save);
574
575 static void rdb_set_collation_exception_list(const char *exception_list);
576 static void rocksdb_set_collation_exception_list(THD *thd, struct SYS_VAR *var,
577 void *var_ptr,
578 const void *save);
579
580 static int rocksdb_validate_update_cf_options(THD *thd, struct SYS_VAR *var,
581 void *save,
582 st_mysql_value *value);
583
584 static void rocksdb_set_update_cf_options(THD *thd, struct SYS_VAR *var,
585 void *var_ptr, const void *save);
586
587 static int rocksdb_check_bulk_load(
588 THD *const thd, struct SYS_VAR *var MY_ATTRIBUTE((__unused__)), void *save,
589 struct st_mysql_value *value);
590
591 static int rocksdb_check_bulk_load_allow_unsorted(
592 THD *const thd, struct SYS_VAR *var MY_ATTRIBUTE((__unused__)), void *save,
593 struct st_mysql_value *value);
594
595 static void rocksdb_set_max_background_jobs(THD *thd, struct SYS_VAR *const var,
596 void *const var_ptr,
597 const void *const save);
598 static void rocksdb_set_max_background_compactions(THD *thd,
599 struct SYS_VAR *const var,
600 void *const var_ptr,
601 const void *const save);
602
603 static void rocksdb_set_bytes_per_sync(THD *thd, struct SYS_VAR *const var,
604 void *const var_ptr,
605 const void *const save);
606 static void rocksdb_set_wal_bytes_per_sync(THD *thd, struct SYS_VAR *const var,
607 void *const var_ptr,
608 const void *const save);
609 static int rocksdb_validate_set_block_cache_size(THD *thd,
610 struct SYS_VAR *const var,
611 void *var_ptr,
612 struct st_mysql_value *value);
613 static int rocksdb_tracing(THD *const thd MY_ATTRIBUTE((__unused__)),
614 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
615 void *const save, struct st_mysql_value *const value,
616 bool trace_block_cache_access = true);
617 static int rocksdb_validate_max_bottom_pri_background_compactions(
618 THD *thd MY_ATTRIBUTE((__unused__)),
619 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)), void *var_ptr,
620 struct st_mysql_value *value);
621 //////////////////////////////////////////////////////////////////////////////
622 // Options definitions
623 //////////////////////////////////////////////////////////////////////////////
624 static const constexpr ulong RDB_MAX_LOCK_WAIT_SECONDS = 1024 * 1024 * 1024;
625 static const constexpr ulong RDB_MAX_ROW_LOCKS = 1024 * 1024 * 1024;
626 static const constexpr ulong RDB_DEFAULT_ROW_LOCKS = 1024 * 1024;
627 static const constexpr ulong RDB_DEFAULT_BULK_LOAD_SIZE = 1000;
628 static const constexpr int RDB_DEFAULT_MAX_BACKGROUND_JOBS = 2;
629 static const constexpr ulong RDB_DEFAULT_BLOCK_SIZE = 0x4000; // 16K
630 static const constexpr ulong RDB_DEFAULT_MAX_TOTAL_WAL_SIZE =
631 0x80000000; // 2GB
632 static const constexpr ulong RDB_DEFAULT_TABLE_CACHE_NUMSHARDBITS = 6;
633 static const constexpr ulong RDB_MAX_BULK_LOAD_SIZE = 1024 * 1024 * 1024;
634 static const constexpr size_t RDB_DEFAULT_MERGE_BUF_SIZE = 64 * 1024 * 1024;
635 static const constexpr size_t RDB_MIN_MERGE_BUF_SIZE = 100;
636 static const constexpr size_t RDB_DEFAULT_MERGE_COMBINE_READ_SIZE =
637 1024 * 1024 * 1024;
638 static const constexpr size_t RDB_MIN_MERGE_COMBINE_READ_SIZE = 100;
639 static const constexpr size_t RDB_DEFAULT_MERGE_TMP_FILE_REMOVAL_DELAY = 0;
640 static const constexpr size_t RDB_MIN_MERGE_TMP_FILE_REMOVAL_DELAY = 0;
641 static const constexpr int64 RDB_DEFAULT_BLOCK_CACHE_SIZE = 512 * 1024 * 1024;
642 static const constexpr int64 RDB_MIN_BLOCK_CACHE_SIZE = 1024;
643 static const constexpr int RDB_MAX_CHECKSUMS_PCT = 100;
644 static const constexpr uint32_t
645 RDB_DEFAULT_FORCE_COMPUTE_MEMTABLE_STATS_CACHETIME = 60 * 1000 * 1000;
646 static const constexpr ulong RDB_DEADLOCK_DETECT_DEPTH = 50;
647 static const constexpr uint ROCKSDB_MAX_BOTTOM_PRI_BACKGROUND_COMPACTIONS = 64;
648 static const constexpr uint64_t RDB_DEFAULT_MAX_COMPACTION_HISTORY = 64;
649
650 static long long rocksdb_block_cache_size = RDB_DEFAULT_BLOCK_CACHE_SIZE;
651 static long long rocksdb_sim_cache_size = 0;
652 static double rocksdb_cache_high_pri_pool_ratio = 0.0;
653 static bool rocksdb_cache_dump = false;
654 /* Use unsigned long long instead of uint64_t because of MySQL compatibility */
655 static unsigned long long // NOLINT(runtime/int)
656 rocksdb_rate_limiter_bytes_per_sec = 0;
657 static unsigned long long // NOLINT(runtime/int)
658 rocksdb_sst_mgr_rate_bytes_per_sec = DEFAULT_SST_MGR_RATE_BYTES_PER_SEC;
659 static unsigned long long rocksdb_delayed_write_rate;
660 static uint32_t rocksdb_max_latest_deadlocks = RDB_DEADLOCK_DETECT_DEPTH;
661 static unsigned long // NOLINT(runtime/int)
662 rocksdb_persistent_cache_size_mb = 0;
663 static ulong rocksdb_info_log_level = rocksdb::InfoLogLevel::ERROR_LEVEL;
664 static char *rocksdb_wal_dir = nullptr;
665 static char *rocksdb_persistent_cache_path = nullptr;
666 static char *rocksdb_wsenv_path = nullptr;
667 static ulong rocksdb_index_type =
668 rocksdb::BlockBasedTableOptions::kBinarySearch;
669 static uint32_t rocksdb_flush_log_at_trx_commit = 1;
670 static uint32_t rocksdb_debug_optimizer_n_rows = 0;
671 static bool rocksdb_force_compute_memtable_stats = true;
672 static uint32_t rocksdb_force_compute_memtable_stats_cachetime =
673 RDB_DEFAULT_FORCE_COMPUTE_MEMTABLE_STATS_CACHETIME;
674 static bool rocksdb_debug_optimizer_no_zero_cardinality = true;
675 static uint32_t rocksdb_debug_cardinality_multiplier = 0;
676 static uint32_t rocksdb_wal_recovery_mode =
677 static_cast<uint32_t>(rocksdb::WALRecoveryMode::kPointInTimeRecovery);
678 static bool rocksdb_track_and_verify_wals_in_manifest = true;
679 static uint32_t rocksdb_stats_level = 0;
680 static uint32_t rocksdb_access_hint_on_compaction_start =
681 rocksdb::Options::AccessHint::NORMAL;
682 static char *rocksdb_compact_cf_name = nullptr;
683 static char *rocksdb_delete_cf_name = nullptr;
684 static char *rocksdb_checkpoint_name = nullptr;
685 static char *rocksdb_block_cache_trace_options_str = nullptr;
686 static char *rocksdb_trace_options_str = nullptr;
687 static bool rocksdb_signal_drop_index_thread = false;
688 static bool rocksdb_strict_collation_check = true;
689 static bool rocksdb_ignore_unknown_options = true;
690 static char *rocksdb_strict_collation_exceptions = nullptr;
691 static bool rocksdb_collect_sst_properties = true;
692 static bool rocksdb_force_flush_memtable_now_var = true;
693 static bool rocksdb_force_flush_memtable_and_lzero_now_var = false;
694 static bool rocksdb_cancel_manual_compactions_var = false;
695 static bool rocksdb_enable_ttl = true;
696 static bool rocksdb_enable_ttl_read_filtering = true;
697 static int rocksdb_debug_ttl_rec_ts = 0;
698 static int rocksdb_debug_ttl_snapshot_ts = 0;
699 static int rocksdb_debug_ttl_read_filter_ts = 0;
700 static bool rocksdb_debug_ttl_ignore_pk = false;
701 static bool rocksdb_reset_stats = false;
702 static uint32_t rocksdb_seconds_between_stat_computes = 3600;
703 static long long rocksdb_compaction_sequential_deletes = 0l;
704 static long long rocksdb_compaction_sequential_deletes_window = 0l;
705 static long long rocksdb_compaction_sequential_deletes_file_size = 0l;
706 #if defined(ROCKSDB_INCLUDE_VALIDATE_TABLES) && ROCKSDB_INCLUDE_VALIDATE_TABLES
707 static uint32_t rocksdb_validate_tables = 1;
708 #endif // defined(ROCKSDB_INCLUDE_VALIDATE_TABLES) &&
709 // ROCKSDB_INCLUDE_VALIDATE_TABLES
710 static char *rocksdb_datadir = nullptr;
711 static char *rocksdb_fs_uri;
712 static uint32_t rocksdb_max_bottom_pri_background_compactions = 0;
713 static uint32_t rocksdb_table_stats_sampling_pct =
714 RDB_DEFAULT_TBL_STATS_SAMPLE_PCT;
715 static uint32_t rocksdb_table_stats_recalc_threshold_pct = 10;
716 static unsigned long long rocksdb_table_stats_recalc_threshold_count = 100ul;
717 static bool rocksdb_table_stats_use_table_scan = 0;
718 static char *opt_rocksdb_fault_injection_options = nullptr;
719 static int32_t rocksdb_table_stats_background_thread_nice_value =
720 THREAD_PRIO_MAX;
721 static unsigned long long rocksdb_table_stats_max_num_rows_scanned = 0ul;
722 static bool rocksdb_enable_bulk_load_api = true;
723 static bool rocksdb_enable_remove_orphaned_dropped_cfs = true;
724 static bool rpl_skip_tx_api_var = false;
725 static bool rocksdb_print_snapshot_conflict_queries = false;
726 static bool rocksdb_large_prefix = true;
727 static bool rocksdb_allow_to_start_after_corruption = false;
728 static ulong rocksdb_write_policy = rocksdb::TxnDBWritePolicy::WRITE_COMMITTED;
729 char *rocksdb_read_free_rpl_tables;
730 ulong rocksdb_max_row_locks;
731 std::mutex rocksdb_read_free_rpl_tables_mutex;
732 #if defined(HAVE_PSI_INTERFACE)
733 Regex_list_handler rdb_read_free_regex_handler(key_rwlock_read_free_rpl_tables);
734 #else
735 Regex_list_handler rdb_read_free_regex_handler;
736 #endif
737 enum read_free_rpl_type { OFF = 0, PK_ONLY, PK_SK };
738 static ulong rocksdb_read_free_rpl = read_free_rpl_type::OFF;
739 static bool rocksdb_error_on_suboptimal_collation = false;
740 static uint32_t rocksdb_stats_recalc_rate = 0;
741 static bool rocksdb_no_create_column_family = false;
742 static uint32_t rocksdb_debug_manual_compaction_delay = 0;
743 static uint32_t rocksdb_max_manual_compactions = 0;
744 static bool rocksdb_rollback_on_timeout = false;
745 static bool rocksdb_enable_insert_with_update_caching = true;
746 /* Use unsigned long long instead of uint64_t because of MySQL compatibility */
747 static unsigned long long rocksdb_max_compaction_history = 0;
748 static bool rocksdb_skip_locks_if_skip_unique_check = false;
749 static bool rocksdb_alter_column_default_inplace = false;
750 static bool rocksdb_instant_ddl = false;
751 bool rocksdb_enable_tmp_table = false;
752
753 std::atomic<uint64_t> rocksdb_row_lock_deadlocks(0);
754 std::atomic<uint64_t> rocksdb_row_lock_wait_timeouts(0);
755 std::atomic<uint64_t> rocksdb_snapshot_conflict_errors(0);
756 std::atomic<uint64_t> rocksdb_wal_group_syncs(0);
757 std::atomic<uint64_t> rocksdb_manual_compactions_processed(0);
758 std::atomic<uint64_t> rocksdb_manual_compactions_cancelled(0);
759 std::atomic<uint64_t> rocksdb_manual_compactions_running(0);
760 std::atomic<uint64_t> rocksdb_manual_compactions_pending(0);
761 #ifndef NDEBUG
762 std::atomic<uint64_t> rocksdb_num_get_for_update_calls(0);
763 #endif
764
765 std::atomic<uint64_t> rocksdb_partial_index_groups_sorted(0);
766 std::atomic<uint64_t> rocksdb_partial_index_groups_materialized(0);
767 std::atomic<uint64_t> rocksdb_partial_index_rows_sorted(0);
768 std::atomic<uint64_t> rocksdb_partial_index_rows_materialized(0);
769
770 15 static int rocksdb_trace_block_cache_access(
771 THD *const thd, struct SYS_VAR *const var, void *const save,
772 struct st_mysql_value *const value) {
773 15 return rocksdb_tracing(thd, var, save, value,
774 15 /* trace_block_cache_accecss = */ true);
775 }
776
777 16 static int rocksdb_trace_queries(THD *const thd, struct SYS_VAR *const var,
778 void *const save,
779 struct st_mysql_value *const value) {
780 16 return rocksdb_tracing(thd, var, save, value,
781 16 /* trace_block_cache_accecss = */ false);
782 }
783
784 31 static int rocksdb_tracing(THD *const thd MY_ATTRIBUTE((__unused__)),
785 struct SYS_VAR *const var, void *const save,
786 struct st_mysql_value *const value,
787 bool trace_block_cache_access) {
788 31 int len = 0;
789
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 const char *const trace_opt_str_raw = value->val_str(value, nullptr, &len);
790
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 29 times.
31 if (trace_opt_str_raw == nullptr) {
791 2 return HA_EXIT_FAILURE;
792 }
793
794 std::string trace_folder =
795
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
29 trace_block_cache_access ? "/block_cache_traces" : "/queries_traces";
796 29 rocksdb::Status s;
797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 if (rdb == nullptr) {
798 return HA_EXIT_FAILURE;
799 }
800 int rc __attribute__((__unused__));
801
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 std::string trace_opt_str(trace_opt_str_raw);
802
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 23 times.
29 if (trace_opt_str.empty()) {
803 // End tracing block cache accesses or queries.
804
9/18
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 6 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 6 times.
✗ Branch 17 not taken.
6 LogPluginErrMsg(INFORMATION_LEVEL, 0,
805 "Stop tracing block cache accesses or queries.\n");
806
4/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 s = trace_block_cache_access ? rdb->EndBlockCacheTrace() : rdb->EndTrace();
807
808
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
6 if (!s.ok()) {
809
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 rc = ha_rocksdb::rdb_error_to_mysql(s);
810 1 return HA_EXIT_FAILURE;
811 }
812 5 *static_cast<const char **>(save) = trace_opt_str_raw;
813 5 return HA_EXIT_SUCCESS;
814 }
815
816 // Start tracing block cache accesses or queries.
817
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 std::stringstream ss(trace_opt_str);
818 23 std::vector<std::string> trace_opts_strs;
819
3/4
✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 23 times.
88 while (ss.good()) {
820 65 std::string substr;
821
1/2
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
65 getline(ss, substr, ':');
822
1/2
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
65 trace_opts_strs.push_back(substr);
823 65 }
824 23 rocksdb::TraceOptions trace_opt;
825 try {
826
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
23 if (trace_opts_strs.size() != 3) {
827
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 throw std::invalid_argument("Incorrect number of arguments.");
828 }
829
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 10 times.
19 trace_opt.sampling_frequency = std::stoull(trace_opts_strs[0]);
830
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 trace_opt.max_trace_file_size = std::stoull(trace_opts_strs[1]);
831
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 } catch (const std::exception &e) {
832
9/18
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 14 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 14 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 14 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 14 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 14 times.
✗ Branch 17 not taken.
14 LogPluginErrMsg(
833 INFORMATION_LEVEL, 0,
834 "Failed to parse trace option string: %s. The correct "
835 "format is sampling_frequency:max_trace_file_size:trace_file_name. "
836 "sampling_frequency and max_trace_file_size are positive integers. "
837 "The block accesses or quries are saved to the "
838 "rocksdb_datadir%s/trace_file_name.\n",
839 trace_opt_str.c_str(), trace_folder.c_str());
840 14 return HA_EXIT_FAILURE;
841 14 }
842 9 const std::string &trace_file_name = trace_opts_strs[2];
843
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (trace_file_name.find("/") != std::string::npos) {
844 LogPluginErrMsg(INFORMATION_LEVEL, 0,
845 "Start tracing failed (trace option string: %s). The file "
846 "name contains directory separator.\n",
847 trace_opt_str.c_str());
848 return HA_EXIT_FAILURE;
849 }
850
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
18 const std::string trace_dir = std::string(rocksdb_datadir) + trace_folder;
851
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 s = rdb->GetEnv()->CreateDirIfMissing(trace_dir);
852
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if (!s.ok()) {
853 LogPluginErrMsg(INFORMATION_LEVEL, 0,
854 "Start tracing failed (trace option string: %s). Failed to "
855 "create the trace directory %s: %s\n",
856 trace_opt_str.c_str(), trace_dir.c_str(),
857 s.ToString().c_str());
858 return HA_EXIT_FAILURE;
859 }
860
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 const std::string trace_file_path = trace_dir + "/" + trace_file_name;
861
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 s = rdb->GetEnv()->FileExists(trace_file_path);
862
7/10
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 6 times.
9 if (s.ok() || !s.IsNotFound()) {
863
10/20
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✗ Branch 19 not taken.
3 LogPluginErrMsg(
864 INFORMATION_LEVEL, 0,
865 "Start tracing failed (trace option string: %s). The trace "
866 "file either already exists or we encountered an error "
867 "when calling rdb->GetEnv()->FileExists. The returned status string "
868 "is: %s\n",
869 trace_opt_str.c_str(), s.ToString().c_str());
870 3 return HA_EXIT_FAILURE;
871 }
872 6 std::unique_ptr<rocksdb::TraceWriter> trace_writer;
873
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 const rocksdb::EnvOptions env_option(rdb->GetDBOptions());
874
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
12 s = rocksdb::NewFileTraceWriter(rdb->GetEnv(), env_option, trace_file_path,
875 6 &trace_writer);
876
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (!s.ok()) {
877 rc = ha_rocksdb::rdb_error_to_mysql(s);
878 return HA_EXIT_FAILURE;
879 }
880
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (trace_block_cache_access) {
881
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 s = rdb->StartBlockCacheTrace(trace_opt, std::move(trace_writer));
882 } else {
883
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 s = rdb->StartTrace(trace_opt, std::move(trace_writer));
884 }
885
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
6 if (!s.ok()) {
886
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 rc = ha_rocksdb::rdb_error_to_mysql(s);
887 1 return HA_EXIT_FAILURE;
888 }
889 // NO_LINT_DEBUG
890
9/18
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 5 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 5 times.
✗ Branch 17 not taken.
5 LogPluginErrMsg(INFORMATION_LEVEL, 0,
891 "Start tracing block cache accesses or queries. Sampling "
892 "frequency: %" PRIu64
893 ", "
894 "Maximum trace file size: %" PRIu64 ", Trace file path %s.\n",
895 trace_opt.sampling_frequency, trace_opt.max_trace_file_size,
896 trace_file_path.c_str());
897 // Save the trace option.
898 5 *static_cast<const char **>(save) = trace_opt_str_raw;
899 5 return HA_EXIT_SUCCESS;
900 29 }
901
902 935 static std::unique_ptr<rocksdb::DBOptions> rdb_init_rocksdb_db_options(void) {
903
1/2
✓ Branch 0 taken 935 times.
✗ Branch 1 not taken.
935 auto o = std::unique_ptr<rocksdb::DBOptions>(new rocksdb::DBOptions());
904
905 935 o->create_if_missing = true;
906
2/4
✓ Branch 0 taken 935 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 935 times.
✗ Branch 3 not taken.
935 o->listeners.push_back(std::make_shared<Rdb_event_listener>(&ddl_manager));
907 935 o->info_log_level = rocksdb::InfoLogLevel::INFO_LEVEL;
908 935 o->max_background_jobs = RDB_DEFAULT_MAX_BACKGROUND_JOBS;
909 935 o->max_subcompactions = DEFAULT_SUBCOMPACTIONS;
910 935 o->max_open_files = -2; // auto-tune to 50% open_files_limit
911 935 o->max_total_wal_size = RDB_DEFAULT_MAX_TOTAL_WAL_SIZE;
912 935 o->table_cache_numshardbits = RDB_DEFAULT_TABLE_CACHE_NUMSHARDBITS;
913
914 935 o->two_write_queues = true;
915 935 o->manual_wal_flush = true;
916 935 return o;
917 }
918
919 static std::unique_ptr<rocksdb::BlockBasedTableOptions>
920 935 rdb_init_rocksdb_tbl_options(void) {
921 auto o = std::unique_ptr<rocksdb::BlockBasedTableOptions>(
922 935 new rocksdb::BlockBasedTableOptions());
923 935 o->block_size = RDB_DEFAULT_BLOCK_SIZE;
924 935 return o;
925 }
926
927 static rocksdb::Env *GetCompositeEnv(std::shared_ptr<rocksdb::FileSystem> fs) {
928 static std::shared_ptr<rocksdb::Env> composite_env =
929 rocksdb::NewCompositeEnv(fs);
930 return composite_env.get();
931 }
932
933 /* DBOptions contains Statistics and needs to be destructed last */
934 static std::unique_ptr<rocksdb::BlockBasedTableOptions> rocksdb_tbl_options =
935 rdb_init_rocksdb_tbl_options();
936 static std::unique_ptr<rocksdb::DBOptions> rocksdb_db_options =
937 rdb_init_rocksdb_db_options();
938
939 static std::shared_ptr<rocksdb::RateLimiter> rocksdb_rate_limiter;
940
941 /* This enum needs to be kept up to date with rocksdb::TxnDBWritePolicy */
942 static const char *write_policy_names[] = {"write_committed", "write_prepared",
943 "write_unprepared", NullS};
944
945 static TYPELIB write_policy_typelib = {array_elements(write_policy_names) - 1,
946 "write_policy_typelib",
947 write_policy_names, nullptr};
948
949 /* This array needs to be kept up to date with myrocks::read_free_rpl_type */
950 static const char *read_free_rpl_names[] = {"OFF", "PK_ONLY", "PK_SK", NullS};
951
952 static TYPELIB read_free_rpl_typelib = {array_elements(read_free_rpl_names) - 1,
953 "read_free_rpl_typelib",
954 read_free_rpl_names, nullptr};
955
956 /* This enum needs to be kept up to date with rocksdb::InfoLogLevel */
957 static const char *info_log_level_names[] = {"debug_level", "info_level",
958 "warn_level", "error_level",
959 "fatal_level", NullS};
960
961 static TYPELIB info_log_level_typelib = {
962 array_elements(info_log_level_names) - 1, "info_log_level_typelib",
963 info_log_level_names, nullptr};
964
965 /* This enum needs to be kept up to date with rocksdb::BottommostLevelCompaction
966 */
967 static const char *bottommost_level_compaction_names[] = {
968 "kSkip", "kIfHaveCompactionFilter", "kForce", "kForceOptimized", NullS};
969
970 static TYPELIB bottommost_level_compaction_typelib = {
971 array_elements(bottommost_level_compaction_names) - 1,
972 "bottommost_level_compaction_typelib", bottommost_level_compaction_names,
973 nullptr};
974
975 11 static void rocksdb_set_rocksdb_info_log_level(
976 THD *const thd MY_ATTRIBUTE((__unused__)),
977 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
978 void *const var_ptr MY_ATTRIBUTE((__unused__)), const void *const save) {
979
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 assert(save != nullptr);
980
981 11 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
982 11 rocksdb_info_log_level = *static_cast<const uint64_t *>(save);
983 11 rocksdb_db_options->info_log->SetInfoLogLevel(
984 11 static_cast<rocksdb::InfoLogLevel>(rocksdb_info_log_level));
985 11 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
986 11 }
987
988 7 static void rocksdb_set_rocksdb_stats_level(THD *const thd,
989 struct SYS_VAR *const var,
990 void *const var_ptr,
991 const void *const save) {
992
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(save != nullptr);
993
994 7 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
995 7 rocksdb_db_options->statistics->set_stats_level(
996 7 static_cast<rocksdb::StatsLevel>(*static_cast<const uint64_t *>(save)));
997 // Actual stats level is defined at rocksdb dbopt::statistics::stats_level_
998 // so adjusting rocksdb_stats_level here to make sure it points to
999 // the correct stats level.
1000 7 rocksdb_stats_level = rocksdb_db_options->statistics->get_stats_level();
1001 7 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
1002 7 }
1003
1004 13 static void rocksdb_set_reset_stats(my_core::THD *const /* unused */,
1005 my_core::SYS_VAR *const /* unused */,
1006 void *const var_ptr,
1007 const void *const save) {
1008
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 assert(save != nullptr);
1009
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 assert(rdb != nullptr);
1010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 assert(rocksdb_stats != nullptr);
1011
1012 13 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
1013
1014 13 *static_cast<bool *>(var_ptr) = *static_cast<const bool *>(save);
1015
1016
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (rocksdb_reset_stats) {
1017
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 rocksdb::Status s = rdb->ResetStats();
1018
1019 // RocksDB will always return success. Let's document this assumption here
1020 // as well so that we'll get immediately notified when contract changes.
1021
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 assert(s == rocksdb::Status::OK());
1022
1023
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 s = rocksdb_stats->Reset();
1024
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 assert(s == rocksdb::Status::OK());
1025 3 }
1026
1027 13 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
1028 13 }
1029
1030 enum rocksdb_flush_log_at_trx_commit_type : unsigned int {
1031 FLUSH_LOG_NEVER = 0,
1032 FLUSH_LOG_SYNC,
1033 FLUSH_LOG_BACKGROUND,
1034 FLUSH_LOG_MAX /* must be last */
1035 };
1036
1037 static int rocksdb_validate_flush_log_at_trx_commit(
1038 THD *const thd,
1039 struct SYS_VAR *const var, /* in: pointer to system variable */
1040 void *var_ptr, /* out: immediate result for update function */
1041 struct st_mysql_value *const value /* in: incoming value */);
1042 static int rocksdb_check_write_disable_wal(
1043 THD *const thd, struct SYS_VAR *var MY_ATTRIBUTE((__unused__)), void *save,
1044 struct st_mysql_value *value);
1045 1205 static void rocksdb_compact_column_family_stub(THD *const thd,
1046 struct SYS_VAR *const var,
1047 void *const var_ptr,
1048 1205 const void *const save) {}
1049
1050 static int rocksdb_compact_column_family(THD *const thd,
1051 struct SYS_VAR *const var,
1052 void *const var_ptr,
1053 struct st_mysql_value *const value);
1054
1055 static const char *index_type_names[] = {"kBinarySearch", "kHashSearch", NullS};
1056
1057 static TYPELIB index_type_typelib = {array_elements(index_type_names) - 1,
1058 "index_type_typelib", index_type_names,
1059 nullptr};
1060
1061 // TODO: 0 means don't wait at all, and we don't support it yet?
1062 static MYSQL_THDVAR_ULONG(lock_wait_timeout,
1063 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1064 "Number of seconds to wait for lock", nullptr,
1065 nullptr, /*default*/ 1, /*min*/ 1,
1066 /*max*/ RDB_MAX_LOCK_WAIT_SECONDS, 0);
1067
1068 static MYSQL_THDVAR_BOOL(deadlock_detect, PLUGIN_VAR_RQCMDARG,
1069 "Enables deadlock detection", nullptr, nullptr, false);
1070
1071 static MYSQL_THDVAR_ULONG(deadlock_detect_depth, PLUGIN_VAR_RQCMDARG,
1072 "Number of transactions deadlock detection will "
1073 "traverse through before assuming deadlock",
1074 nullptr, nullptr,
1075 /*default*/ RDB_DEADLOCK_DETECT_DEPTH,
1076 /*min*/ 2,
1077 /*max*/ ULONG_MAX, 0);
1078
1079 static MYSQL_THDVAR_BOOL(
1080 commit_time_batch_for_recovery, PLUGIN_VAR_RQCMDARG,
1081 "TransactionOptions::commit_time_batch_for_recovery for RocksDB", nullptr,
1082 nullptr, false);
1083
1084 static MYSQL_THDVAR_BOOL(
1085 trace_sst_api, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1086 "Generate trace output in the log for each call to the SstFileWriter",
1087 nullptr, nullptr, false);
1088
1089 static MYSQL_THDVAR_BOOL(
1090 bulk_load, PLUGIN_VAR_RQCMDARG,
1091 "Use bulk-load mode for inserts. This disables "
1092 "unique_checks and enables rocksdb_commit_in_the_middle.",
1093 rocksdb_check_bulk_load, nullptr, false);
1094
1095 static MYSQL_THDVAR_BOOL(bulk_load_allow_sk, PLUGIN_VAR_RQCMDARG,
1096 "Allow bulk loading of sk keys during bulk-load. "
1097 "Can be changed only when bulk load is disabled.",
1098 /* Intentionally reuse unsorted's check function */
1099 rocksdb_check_bulk_load_allow_unsorted, nullptr,
1100 false);
1101
1102 static MYSQL_THDVAR_BOOL(bulk_load_allow_unsorted, PLUGIN_VAR_RQCMDARG,
1103 "Allow unsorted input during bulk-load. "
1104 "Can be changed only when bulk load is disabled.",
1105 rocksdb_check_bulk_load_allow_unsorted, nullptr,
1106 false);
1107
1108 static MYSQL_SYSVAR_BOOL(enable_bulk_load_api, rocksdb_enable_bulk_load_api,
1109 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1110 "Enables using SstFileWriter for bulk loading",
1111 nullptr, nullptr, rocksdb_enable_bulk_load_api);
1112
1113 static MYSQL_SYSVAR_BOOL(
1114 enable_pipelined_write,
1115 *reinterpret_cast<bool *>(&rocksdb_db_options->enable_pipelined_write),
1116 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1117 "DBOptions::enable_pipelined_write for RocksDB", nullptr, nullptr,
1118 rocksdb_db_options->enable_pipelined_write);
1119
1120 static MYSQL_SYSVAR_BOOL(enable_remove_orphaned_dropped_cfs,
1121 rocksdb_enable_remove_orphaned_dropped_cfs,
1122 PLUGIN_VAR_RQCMDARG,
1123 "Enables removing dropped cfs from metadata if it "
1124 "doesn't exist in cf manager",
1125 nullptr, nullptr,
1126 rocksdb_enable_remove_orphaned_dropped_cfs);
1127
1128 static MYSQL_THDVAR_STR(tmpdir, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC,
1129 "Directory for temporary files during DDL operations.",
1130 nullptr, nullptr, "");
1131
1132 static MYSQL_THDVAR_BOOL(
1133 commit_in_the_middle, PLUGIN_VAR_RQCMDARG,
1134 "Commit rows implicitly every rocksdb_bulk_load_size, on bulk load/insert, "
1135 "update and delete",
1136 nullptr, nullptr, false);
1137
1138 #if defined(ROCKSDB_INCLUDE_RFR) && ROCKSDB_INCLUDE_RFR
1139
1140 static MYSQL_THDVAR_BOOL(
1141 blind_delete_primary_key, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1142 "Deleting rows by primary key lookup, without reading rows (Blind Deletes)."
1143 " Blind delete is disabled if the table has secondary key",
1144 nullptr, nullptr, false);
1145
1146 static MYSQL_THDVAR_BOOL(
1147 enable_iterate_bounds, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1148 "Enable rocksdb iterator upper/lower bounds in read options.", nullptr,
1149 nullptr, true);
1150
1151 static const char *DEFAULT_READ_FREE_RPL_TABLES = ".*";
1152
1153 1882 static std::regex_constants::syntax_option_type get_regex_flags() {
1154 1882 std::regex_constants::syntax_option_type flags =
1155 std::regex::nosubs | std::regex::extended;
1156
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 1854 times.
1882 if (lower_case_table_names) {
1157 28 flags |= std::regex::icase;
1158 }
1159 1882 return flags;
1160 }
1161
1162 5 static int rocksdb_validate_read_free_rpl_tables(
1163 THD *thd MY_ATTRIBUTE((__unused__)),
1164 struct SYS_VAR *var MY_ATTRIBUTE((__unused__)), void *save,
1165 struct st_mysql_value *value) {
1166 char buff[STRING_BUFFER_USUAL_SIZE];
1167 5 int length = sizeof(buff);
1168
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 const char *wlist_buf = value->val_str(value, buff, &length);
1169
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (wlist_buf)
1170
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 wlist_buf = thd->strmake(wlist_buf, length); // make a temp copy
1171
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 const auto wlist = wlist_buf ? wlist_buf : DEFAULT_READ_FREE_RPL_TABLES;
1172
1173 #if defined(HAVE_PSI_INTERFACE)
1174
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 Regex_list_handler regex_handler(key_rwlock_read_free_rpl_tables);
1175 #else
1176 Regex_list_handler regex_handler;
1177 #endif
1178
1179
4/6
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 4 times.
5 if (!regex_handler.set_patterns(wlist, get_regex_flags())) {
1180
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 warn_about_bad_patterns(&regex_handler, "rocksdb_read_free_rpl_tables");
1181 1 return HA_EXIT_FAILURE;
1182 }
1183
1184 4 *static_cast<const char **>(save) = wlist;
1185 4 return HA_EXIT_SUCCESS;
1186 5 }
1187
1188 7 static void rocksdb_update_read_free_rpl_tables(
1189 THD *thd MY_ATTRIBUTE((__unused__)),
1190 struct SYS_VAR *var MY_ATTRIBUTE((__unused__)), void *var_ptr,
1191 const void *save) {
1192 7 const auto wlist = *static_cast<const char *const *>(save);
1193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(wlist != nullptr);
1194
1195 // This is bound to succeed since we've already checked for bad patterns in
1196 // rocksdb_validate_read_free_rpl_tables
1197
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 rdb_read_free_regex_handler.set_patterns(wlist, get_regex_flags());
1198
1199 // update all table defs
1200 struct Rdb_read_free_rpl_updater : public Rdb_tables_scanner {
1201 int add_table(Rdb_tbl_def *tdef) override {
1202 tdef->check_and_set_read_free_rpl_table();
1203 return HA_EXIT_SUCCESS;
1204 }
1205 7 } updater;
1206
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 ddl_manager.scan_for_tables(&updater);
1207
1208 7 *static_cast<const char **>(var_ptr) = *static_cast<char *const *>(save);
1209 7 }
1210
1211 913 static void rocksdb_set_max_bottom_pri_background_compactions_internal(
1212 uint val) {
1213 // Set lower priority for compactions
1214
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 896 times.
913 if (val > 0) {
1215 // This creates background threads in rocksdb with BOTTOM priority pool.
1216 // Compactions for bottommost level use threads in the BOTTOM pool, and
1217 // the threads in the BOTTOM pool run with lower OS priority (19 in Linux).
1218 17 rdb->GetEnv()->SetBackgroundThreads(val, rocksdb::Env::Priority::BOTTOM);
1219 17 rdb->GetEnv()->LowerThreadPoolCPUPriority(rocksdb::Env::Priority::BOTTOM);
1220
8/16
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 17 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 17 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 17 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 17 times.
✗ Branch 15 not taken.
17 LogPluginErrMsg(INFORMATION_LEVEL, 0,
1221 "Set %d compaction thread(s) with "
1222 "lower scheduling priority.",
1223 val);
1224 }
1225 913 }
1226
1227 static MYSQL_SYSVAR_STR(
1228 read_free_rpl_tables, rocksdb_read_free_rpl_tables,
1229 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
1230 "Regex that describes set of tables that will use read-free replication "
1231 "on the slave (i.e. not lookup a row during replication)",
1232 rocksdb_validate_read_free_rpl_tables, rocksdb_update_read_free_rpl_tables,
1233 DEFAULT_READ_FREE_RPL_TABLES);
1234
1235 static MYSQL_SYSVAR_ENUM(
1236 read_free_rpl, rocksdb_read_free_rpl,
1237 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
1238 "Use read-free replication on the slave (i.e. no row lookup during "
1239 "replication). Default is OFF, PK_SK will enable it on all tables with "
1240 "primary key. PK_ONLY will enable it on tables where the only key is the "
1241 "primary key (i.e. no secondary keys).",
1242 nullptr, nullptr, read_free_rpl_type::OFF, &read_free_rpl_typelib);
1243 #endif // defined(ROCKSDB_INCLUDE_RFR) && ROCKSDB_INCLUDE_RFR
1244
1245 static MYSQL_SYSVAR_BOOL(
1246 rpl_skip_tx_api, rpl_skip_tx_api_var, PLUGIN_VAR_RQCMDARG,
1247 "Use write batches for replication thread instead of tx api", nullptr,
1248 nullptr, false);
1249
1250 static MYSQL_THDVAR_BOOL(skip_bloom_filter_on_read,
1251 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1252 "Skip using bloom filter for reads", nullptr, nullptr,
1253 false);
1254
1255 static MYSQL_SYSVAR_ULONG(max_row_locks, rocksdb_max_row_locks,
1256 PLUGIN_VAR_RQCMDARG,
1257 "Maximum number of locks a transaction can have",
1258 nullptr, nullptr,
1259 /*default*/ RDB_DEFAULT_ROW_LOCKS,
1260 /*min*/ 1,
1261 /*max*/ RDB_MAX_ROW_LOCKS, 0);
1262
1263 static MYSQL_THDVAR_ULONGLONG(
1264 write_batch_max_bytes, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1265 "Maximum size of write batch in bytes. 0 means no limit.", nullptr, nullptr,
1266 /* default */ 0, /* min */ 0, /* max */ SIZE_T_MAX, 1);
1267
1268 static MYSQL_THDVAR_ULONGLONG(
1269 write_batch_flush_threshold,
1270 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1271 "Maximum size of write batch in bytes before flushing. Only valid if "
1272 "rocksdb_write_policy is WRITE_UNPREPARED. 0 means no limit.",
1273 nullptr, nullptr, /* default */ 0, /* min */ 0, /* max */ SIZE_T_MAX, 1);
1274
1275 static MYSQL_THDVAR_BOOL(
1276 lock_scanned_rows, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1277 "Take and hold locks on rows that are scanned but not updated", nullptr,
1278 nullptr, false);
1279
1280 static MYSQL_THDVAR_ULONG(bulk_load_size,
1281 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1282 "Max #records in a batch for bulk-load mode", nullptr,
1283 nullptr,
1284 /*default*/ RDB_DEFAULT_BULK_LOAD_SIZE,
1285 /*min*/ 1,
1286 /*max*/ RDB_MAX_BULK_LOAD_SIZE, 0);
1287
1288 static MYSQL_THDVAR_BOOL(
1289 bulk_load_partial_index, PLUGIN_VAR_RQCMDARG,
1290 "Materialize partial index during bulk load, instead of leaving it empty.",
1291 nullptr, nullptr, true);
1292
1293 static MYSQL_THDVAR_ULONGLONG(
1294 merge_buf_size, PLUGIN_VAR_RQCMDARG,
1295 "Size to allocate for merge sort buffers written out to disk "
1296 "during inplace index creation.",
1297 nullptr, nullptr,
1298 /* default (64MB) */ RDB_DEFAULT_MERGE_BUF_SIZE,
1299 /* min (100B) */ RDB_MIN_MERGE_BUF_SIZE,
1300 /* max */ SIZE_T_MAX, 1);
1301
1302 static MYSQL_THDVAR_ULONGLONG(
1303 merge_combine_read_size, PLUGIN_VAR_RQCMDARG,
1304 "Size that we have to work with during combine (reading from disk) phase "
1305 "of "
1306 "external sort during fast index creation.",
1307 nullptr, nullptr,
1308 /* default (1GB) */ RDB_DEFAULT_MERGE_COMBINE_READ_SIZE,
1309 /* min (100B) */ RDB_MIN_MERGE_COMBINE_READ_SIZE,
1310 /* max */ SIZE_T_MAX, 1);
1311
1312 static MYSQL_THDVAR_ULONGLONG(
1313 merge_tmp_file_removal_delay_ms, PLUGIN_VAR_RQCMDARG,
1314 "Fast index creation creates a large tmp file on disk during index "
1315 "creation. Removing this large file all at once when index creation is "
1316 "complete can cause trim stalls on Flash. This variable specifies a "
1317 "duration to sleep (in milliseconds) between calling chsize() to truncate "
1318 "the file in chunks. The chunk size is the same as merge_buf_size.",
1319 nullptr, nullptr,
1320 /* default (0ms) */ RDB_DEFAULT_MERGE_TMP_FILE_REMOVAL_DELAY,
1321 /* min (0ms) */ RDB_MIN_MERGE_TMP_FILE_REMOVAL_DELAY,
1322 /* max */ SIZE_T_MAX, 1);
1323
1324 static MYSQL_THDVAR_INT(
1325 manual_compaction_threads, PLUGIN_VAR_RQCMDARG,
1326 "How many rocksdb threads to run for manual compactions", nullptr, nullptr,
1327 /* default rocksdb.dboption max_subcompactions */ 0,
1328 /* min */ 0, /* max */ 128, 0);
1329
1330 static MYSQL_THDVAR_ENUM(
1331 manual_compaction_bottommost_level, PLUGIN_VAR_RQCMDARG,
1332 "Option for bottommost level compaction during manual "
1333 "compaction",
1334 nullptr, nullptr,
1335 /* default */
1336 (ulong)rocksdb::BottommostLevelCompaction::kForceOptimized,
1337 &bottommost_level_compaction_typelib);
1338
1339 static MYSQL_SYSVAR_BOOL(
1340 create_if_missing,
1341 *static_cast<bool *>(&rocksdb_db_options->create_if_missing),
1342 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1343 "DBOptions::create_if_missing for RocksDB", nullptr, nullptr,
1344 rocksdb_db_options->create_if_missing);
1345
1346 static void concurrent_prepare_update(THD *thd, SYS_VAR *var, void *var_ptr,
1347 const void *save) {
1348 push_warning(thd, Sql_condition::SL_WARNING, HA_ERR_WRONG_COMMAND,
1349 "Using rocksdb_concurrent_prepare is deprecated and the "
1350 "parameter may be removed in future releases.");
1351 }
1352
1353 static MYSQL_SYSVAR_BOOL(
1354 concurrent_prepare,
1355 *static_cast<bool *>(&rocksdb_db_options->two_write_queues),
1356 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1357 "DEPRECATED, use rocksdb_two_write_queries instead.", nullptr,
1358 concurrent_prepare_update, rocksdb_db_options->two_write_queues);
1359
1360 static MYSQL_SYSVAR_BOOL(
1361 two_write_queues,
1362 *static_cast<bool *>(&rocksdb_db_options->two_write_queues),
1363 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1364 "DBOptions::two_write_queues for RocksDB", nullptr, nullptr,
1365 rocksdb_db_options->two_write_queues);
1366
1367 static MYSQL_SYSVAR_BOOL(
1368 manual_wal_flush,
1369 *static_cast<bool *>(&rocksdb_db_options->manual_wal_flush),
1370 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1371 "DBOptions::manual_wal_flush for RocksDB", nullptr, nullptr,
1372 rocksdb_db_options->manual_wal_flush);
1373
1374 static MYSQL_SYSVAR_ENUM(write_policy, rocksdb_write_policy,
1375 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1376 "DBOptions::write_policy for RocksDB", nullptr,
1377 nullptr, rocksdb::TxnDBWritePolicy::WRITE_COMMITTED,
1378 &write_policy_typelib);
1379
1380 static MYSQL_SYSVAR_BOOL(
1381 create_missing_column_families,
1382 *static_cast<bool *>(&rocksdb_db_options->create_missing_column_families),
1383 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1384 "DBOptions::create_missing_column_families for RocksDB", nullptr, nullptr,
1385 rocksdb_db_options->create_missing_column_families);
1386
1387 static MYSQL_SYSVAR_BOOL(
1388 error_if_exists, *static_cast<bool *>(&rocksdb_db_options->error_if_exists),
1389 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1390 "DBOptions::error_if_exists for RocksDB", nullptr, nullptr,
1391 rocksdb_db_options->error_if_exists);
1392
1393 static MYSQL_SYSVAR_BOOL(
1394 paranoid_checks, *static_cast<bool *>(&rocksdb_db_options->paranoid_checks),
1395 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1396 "DBOptions::paranoid_checks for RocksDB", nullptr, nullptr,
1397 rocksdb_db_options->paranoid_checks);
1398
1399 static MYSQL_SYSVAR_ULONGLONG(
1400 rate_limiter_bytes_per_sec, rocksdb_rate_limiter_bytes_per_sec,
1401 PLUGIN_VAR_RQCMDARG, "DBOptions::rate_limiter bytes_per_sec for RocksDB",
1402 nullptr, rocksdb_set_rate_limiter_bytes_per_sec, /* default */ 0L,
1403 /* min */ 0L, /* max */ MAX_RATE_LIMITER_BYTES_PER_SEC, 0);
1404
1405 static MYSQL_SYSVAR_ULONGLONG(
1406 sst_mgr_rate_bytes_per_sec, rocksdb_sst_mgr_rate_bytes_per_sec,
1407 PLUGIN_VAR_RQCMDARG,
1408 "DBOptions::sst_file_manager rate_bytes_per_sec for RocksDB", nullptr,
1409 rocksdb_set_sst_mgr_rate_bytes_per_sec,
1410 /* default */ DEFAULT_SST_MGR_RATE_BYTES_PER_SEC,
1411 /* min */ 0L, /* max */ UINT64_MAX, 0);
1412
1413 static MYSQL_SYSVAR_ULONGLONG(delayed_write_rate, rocksdb_delayed_write_rate,
1414 PLUGIN_VAR_RQCMDARG,
1415 "DBOptions::delayed_write_rate", nullptr,
1416 rocksdb_set_delayed_write_rate,
1417 rocksdb_db_options->delayed_write_rate, 0,
1418 UINT64_MAX, 0);
1419
1420 static MYSQL_SYSVAR_UINT(max_latest_deadlocks, rocksdb_max_latest_deadlocks,
1421 PLUGIN_VAR_RQCMDARG,
1422 "Maximum number of recent "
1423 "deadlocks to store",
1424 nullptr, rocksdb_set_max_latest_deadlocks,
1425 rocksdb::kInitialMaxDeadlocks, 0, UINT32_MAX, 0);
1426
1427 static MYSQL_SYSVAR_ENUM(
1428 info_log_level, rocksdb_info_log_level, PLUGIN_VAR_RQCMDARG,
1429 "Filter level for info logs to be written mysqld error log. "
1430 "Valid values include 'debug_level', 'info_level', 'warn_level'"
1431 "'error_level' and 'fatal_level'.",
1432 nullptr, rocksdb_set_rocksdb_info_log_level,
1433 rocksdb::InfoLogLevel::ERROR_LEVEL, &info_log_level_typelib);
1434
1435 static MYSQL_THDVAR_INT(
1436 perf_context_level, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1437 "Perf Context Level for rocksdb internal timer stat collection", nullptr,
1438 nullptr,
1439 /* default */ rocksdb::PerfLevel::kUninitialized,
1440 /* min */ rocksdb::PerfLevel::kUninitialized,
1441 /* max */ rocksdb::PerfLevel::kOutOfBounds - 1, 0);
1442
1443 static MYSQL_SYSVAR_UINT(
1444 wal_recovery_mode, rocksdb_wal_recovery_mode, PLUGIN_VAR_RQCMDARG,
1445 "DBOptions::wal_recovery_mode for RocksDB. Default is kPointInTimeRecovery",
1446 nullptr, nullptr,
1447 /* default */ (uint)rocksdb::WALRecoveryMode::kPointInTimeRecovery,
1448 /* min */ (uint)rocksdb::WALRecoveryMode::kTolerateCorruptedTailRecords,
1449 /* max */ (uint)rocksdb::WALRecoveryMode::kSkipAnyCorruptedRecords, 0);
1450
1451 static MYSQL_SYSVAR_BOOL(
1452 track_and_verify_wals_in_manifest,
1453 *reinterpret_cast<bool *>(&rocksdb_track_and_verify_wals_in_manifest),
1454 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1455 "DBOptions::track_and_verify_wals_in_manifest for RocksDB", nullptr,
1456 nullptr, true);
1457
1458 static MYSQL_SYSVAR_UINT(
1459 stats_level, rocksdb_stats_level, PLUGIN_VAR_RQCMDARG,
1460 "Statistics Level for RocksDB. Default is 1 (kExceptHistogramOrTimers)",
1461 nullptr, rocksdb_set_rocksdb_stats_level,
1462 /* default */ (uint)rocksdb::StatsLevel::kExceptHistogramOrTimers,
1463 /* min */ (uint)rocksdb::StatsLevel::kExceptTickers,
1464 /* max */ (uint)rocksdb::StatsLevel::kAll, 0);
1465
1466 static MYSQL_SYSVAR_ULONG(compaction_readahead_size,
1467 rocksdb_db_options->compaction_readahead_size,
1468 PLUGIN_VAR_RQCMDARG,
1469 "DBOptions::compaction_readahead_size for RocksDB",
1470 nullptr, nullptr,
1471 rocksdb_db_options->compaction_readahead_size,
1472 /* min */ 0L, /* max */ ULONG_MAX, 0);
1473
1474 static MYSQL_SYSVAR_UINT(
1475 access_hint_on_compaction_start, rocksdb_access_hint_on_compaction_start,
1476 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1477 "DBOptions::access_hint_on_compaction_start for RocksDB", nullptr, nullptr,
1478 /* default */ (uint)rocksdb::Options::AccessHint::NORMAL,
1479 /* min */ (uint)rocksdb::Options::AccessHint::NONE,
1480 /* max */ (uint)rocksdb::Options::AccessHint::WILLNEED, 0);
1481
1482 static MYSQL_SYSVAR_BOOL(
1483 allow_concurrent_memtable_write,
1484 *static_cast<bool *>(&rocksdb_db_options->allow_concurrent_memtable_write),
1485 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1486 "DBOptions::allow_concurrent_memtable_write for RocksDB", nullptr, nullptr,
1487 false);
1488
1489 static MYSQL_SYSVAR_BOOL(
1490 enable_write_thread_adaptive_yield,
1491 *static_cast<bool *>(
1492 &rocksdb_db_options->enable_write_thread_adaptive_yield),
1493 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1494 "DBOptions::enable_write_thread_adaptive_yield for RocksDB", nullptr,
1495 nullptr, false);
1496
1497 static MYSQL_SYSVAR_INT(max_open_files, rocksdb_db_options->max_open_files,
1498 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1499 "DBOptions::max_open_files for RocksDB", nullptr,
1500 nullptr, rocksdb_db_options->max_open_files,
1501 /* min */ -2, /* max */ INT_MAX, 0);
1502
1503 static MYSQL_SYSVAR_UINT64_T(max_total_wal_size,
1504 rocksdb_db_options->max_total_wal_size,
1505 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1506 "DBOptions::max_total_wal_size for RocksDB",
1507 nullptr, nullptr,
1508 rocksdb_db_options->max_total_wal_size,
1509 /* min */ 0L, /* max */ LONG_MAX, 0);
1510
1511 static MYSQL_SYSVAR_BOOL(use_fsync,
1512 *static_cast<bool *>(&rocksdb_db_options->use_fsync),
1513 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1514 "DBOptions::use_fsync for RocksDB", nullptr, nullptr,
1515 rocksdb_db_options->use_fsync);
1516
1517 static MYSQL_SYSVAR_STR(wal_dir, rocksdb_wal_dir,
1518 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1519 "DBOptions::wal_dir for RocksDB", nullptr, nullptr,
1520 rocksdb_db_options->wal_dir.c_str());
1521
1522 static MYSQL_SYSVAR_STR(
1523 persistent_cache_path, rocksdb_persistent_cache_path,
1524 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1525 "Path for BlockBasedTableOptions::persistent_cache for RocksDB", nullptr,
1526 nullptr, "");
1527
1528 static MYSQL_SYSVAR_ULONG(
1529 persistent_cache_size_mb, rocksdb_persistent_cache_size_mb,
1530 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1531 "Size of cache in MB for BlockBasedTableOptions::persistent_cache "
1532 "for RocksDB",
1533 nullptr, nullptr, rocksdb_persistent_cache_size_mb,
1534 /* min */ 0L, /* max */ ULONG_MAX, 0);
1535
1536 static MYSQL_SYSVAR_STR(wsenv_path, rocksdb_wsenv_path,
1537 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1538 "Path for RocksDB WSEnv", nullptr, nullptr, "");
1539
1540 static MYSQL_SYSVAR_STR(fault_injection_options,
1541 opt_rocksdb_fault_injection_options,
1542 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1543 "Fault injection options for running rocksdb tests",
1544 nullptr, nullptr, nullptr);
1545
1546 static MYSQL_SYSVAR_UINT64_T(
1547 delete_obsolete_files_period_micros,
1548 rocksdb_db_options->delete_obsolete_files_period_micros,
1549 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1550 "DBOptions::delete_obsolete_files_period_micros for RocksDB", nullptr,
1551 nullptr, rocksdb_db_options->delete_obsolete_files_period_micros,
1552 /* min */ 0L, /* max */ LONG_MAX, 0);
1553
1554 static MYSQL_SYSVAR_INT(max_background_jobs,
1555 rocksdb_db_options->max_background_jobs,
1556 PLUGIN_VAR_RQCMDARG,
1557 "DBOptions::max_background_jobs for RocksDB", nullptr,
1558 rocksdb_set_max_background_jobs,
1559 rocksdb_db_options->max_background_jobs,
1560 /* min */ -1, /* max */ MAX_BACKGROUND_JOBS, 0);
1561
1562 static MYSQL_SYSVAR_INT(max_background_flushes,
1563 rocksdb_db_options->max_background_flushes,
1564 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1565 "DBOptions::max_background_flushes for RocksDB",
1566 nullptr, nullptr,
1567 rocksdb_db_options->max_background_flushes,
1568 /* min */ -1, /* max */ 64, 0);
1569
1570 static MYSQL_SYSVAR_INT(max_background_compactions,
1571 rocksdb_db_options->max_background_compactions,
1572 PLUGIN_VAR_RQCMDARG,
1573 "DBOptions::max_background_compactions for RocksDB",
1574 nullptr, rocksdb_set_max_background_compactions,
1575 rocksdb_db_options->max_background_compactions,
1576 /* min */ -1, /* max */ 64, 0);
1577
1578 static MYSQL_SYSVAR_UINT(
1579 max_bottom_pri_background_compactions,
1580 rocksdb_max_bottom_pri_background_compactions, PLUGIN_VAR_RQCMDARG,
1581 "Creating specified number of threads, setting lower "
1582 "CPU priority, and letting Lmax compactions use them. "
1583 "Maximum total compaction concurrency continues to be capped to "
1584 "rocksdb_max_background_compactions or "
1585 "rocksdb_max_background_jobs. In addition to that, Lmax "
1586 "compaction concurrency is capped to "
1587 "rocksdb_max_bottom_pri_background_compactions. Default value is 0, "
1588 "which means all compactions are under concurrency of "
1589 "rocksdb_max_background_compactions|jobs. If you set very low "
1590 "rocksdb_max_bottom_pri_background_compactions (e.g. 1 or 2), compactions "
1591 "may not be able to keep up. Since Lmax normally has "
1592 "90 percent of data, it is recommended to set closer number to "
1593 "rocksdb_max_background_compactions|jobs. This option is helpful to "
1594 "give more CPU resources to other threads (e.g. query processing).",
1595 rocksdb_validate_max_bottom_pri_background_compactions, nullptr, 0,
1596 /* min */ 0, /* max */ ROCKSDB_MAX_BOTTOM_PRI_BACKGROUND_COMPACTIONS, 0);
1597
1598 static MYSQL_SYSVAR_UINT(max_subcompactions,
1599 rocksdb_db_options->max_subcompactions,
1600 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1601 "DBOptions::max_subcompactions for RocksDB", nullptr,
1602 nullptr, rocksdb_db_options->max_subcompactions,
1603 /* min */ 1, /* max */ MAX_SUBCOMPACTIONS, 0);
1604
1605 static MYSQL_SYSVAR_ULONG(max_log_file_size,
1606 rocksdb_db_options->max_log_file_size,
1607 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1608 "DBOptions::max_log_file_size for RocksDB", nullptr,
1609 nullptr, rocksdb_db_options->max_log_file_size,
1610 /* min */ 0L, /* max */ LONG_MAX, 0);
1611
1612 static MYSQL_SYSVAR_ULONG(log_file_time_to_roll,
1613 rocksdb_db_options->log_file_time_to_roll,
1614 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1615 "DBOptions::log_file_time_to_roll for RocksDB",
1616 nullptr, nullptr,
1617 rocksdb_db_options->log_file_time_to_roll,
1618 /* min */ 0L, /* max */ LONG_MAX, 0);
1619
1620 static MYSQL_SYSVAR_ULONG(keep_log_file_num,
1621 rocksdb_db_options->keep_log_file_num,
1622 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1623 "DBOptions::keep_log_file_num for RocksDB", nullptr,
1624 nullptr, rocksdb_db_options->keep_log_file_num,
1625 /* min */ 0L, /* max */ LONG_MAX, 0);
1626
1627 static MYSQL_SYSVAR_UINT64_T(max_manifest_file_size,
1628 rocksdb_db_options->max_manifest_file_size,
1629 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1630 "DBOptions::max_manifest_file_size for RocksDB",
1631 nullptr, nullptr,
1632 rocksdb_db_options->max_manifest_file_size,
1633 /* min */ 0L, /* max */ ULONG_MAX, 0);
1634
1635 static MYSQL_SYSVAR_INT(table_cache_numshardbits,
1636 rocksdb_db_options->table_cache_numshardbits,
1637 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1638 "DBOptions::table_cache_numshardbits for RocksDB",
1639 nullptr, nullptr,
1640 rocksdb_db_options->table_cache_numshardbits,
1641 /* min */ 0, /* max */ 19, 0);
1642
1643 static MYSQL_SYSVAR_UINT64_T(wal_ttl_seconds,
1644 rocksdb_db_options->WAL_ttl_seconds,
1645 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1646 "DBOptions::WAL_ttl_seconds for RocksDB", nullptr,
1647 nullptr, rocksdb_db_options->WAL_ttl_seconds,
1648 /* min */ 0L, /* max */ LONG_MAX, 0);
1649
1650 static MYSQL_SYSVAR_UINT64_T(wal_size_limit_mb,
1651 rocksdb_db_options->WAL_size_limit_MB,
1652 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1653 "DBOptions::WAL_size_limit_MB for RocksDB",
1654 nullptr, nullptr,
1655 rocksdb_db_options->WAL_size_limit_MB,
1656 /* min */ 0L, /* max */ LONG_MAX, 0);
1657
1658 static MYSQL_SYSVAR_ULONG(manifest_preallocation_size,
1659 rocksdb_db_options->manifest_preallocation_size,
1660 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1661 "DBOptions::manifest_preallocation_size for RocksDB",
1662 nullptr, nullptr,
1663 rocksdb_db_options->manifest_preallocation_size,
1664 /* min */ 0L, /* max */ LONG_MAX, 0);
1665
1666 static MYSQL_SYSVAR_BOOL(
1667 use_direct_reads,
1668 *static_cast<bool *>(&rocksdb_db_options->use_direct_reads),
1669 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1670 "DBOptions::use_direct_reads for RocksDB", nullptr, nullptr,
1671 rocksdb_db_options->use_direct_reads);
1672
1673 static MYSQL_SYSVAR_BOOL(
1674 use_direct_io_for_flush_and_compaction,
1675 *static_cast<bool *>(
1676 &rocksdb_db_options->use_direct_io_for_flush_and_compaction),
1677 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1678 "DBOptions::use_direct_io_for_flush_and_compaction for RocksDB", nullptr,
1679 nullptr, rocksdb_db_options->use_direct_io_for_flush_and_compaction);
1680
1681 static MYSQL_SYSVAR_BOOL(
1682 allow_mmap_reads,
1683 *static_cast<bool *>(&rocksdb_db_options->allow_mmap_reads),
1684 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1685 "DBOptions::allow_mmap_reads for RocksDB", nullptr, nullptr,
1686 rocksdb_db_options->allow_mmap_reads);
1687
1688 static MYSQL_SYSVAR_BOOL(
1689 allow_mmap_writes,
1690 *static_cast<bool *>(&rocksdb_db_options->allow_mmap_writes),
1691 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1692 "DBOptions::allow_mmap_writes for RocksDB", nullptr, nullptr,
1693 rocksdb_db_options->allow_mmap_writes);
1694
1695 static MYSQL_SYSVAR_BOOL(
1696 is_fd_close_on_exec,
1697 *static_cast<bool *>(&rocksdb_db_options->is_fd_close_on_exec),
1698 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1699 "DBOptions::is_fd_close_on_exec for RocksDB", nullptr, nullptr,
1700 rocksdb_db_options->is_fd_close_on_exec);
1701
1702 static MYSQL_SYSVAR_UINT(stats_dump_period_sec,
1703 rocksdb_db_options->stats_dump_period_sec,
1704 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1705 "DBOptions::stats_dump_period_sec for RocksDB",
1706 nullptr, nullptr,
1707 rocksdb_db_options->stats_dump_period_sec,
1708 /* min */ 0, /* max */ INT_MAX, 0);
1709
1710 static MYSQL_SYSVAR_BOOL(
1711 advise_random_on_open,
1712 *static_cast<bool *>(&rocksdb_db_options->advise_random_on_open),
1713 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1714 "DBOptions::advise_random_on_open for RocksDB", nullptr, nullptr,
1715 rocksdb_db_options->advise_random_on_open);
1716
1717 static MYSQL_SYSVAR_ULONG(db_write_buffer_size,
1718 rocksdb_db_options->db_write_buffer_size,
1719 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1720 "DBOptions::db_write_buffer_size for RocksDB",
1721 nullptr, nullptr,
1722 rocksdb_db_options->db_write_buffer_size,
1723 /* min */ 0L, /* max */ LONG_MAX, 0);
1724
1725 static MYSQL_SYSVAR_BOOL(
1726 use_adaptive_mutex,
1727 *static_cast<bool *>(&rocksdb_db_options->use_adaptive_mutex),
1728 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1729 "DBOptions::use_adaptive_mutex for RocksDB", nullptr, nullptr,
1730 rocksdb_db_options->use_adaptive_mutex);
1731
1732 static MYSQL_SYSVAR_UINT64_T(bytes_per_sync, rocksdb_db_options->bytes_per_sync,
1733 PLUGIN_VAR_RQCMDARG,
1734 "DBOptions::bytes_per_sync for RocksDB", nullptr,
1735 rocksdb_set_bytes_per_sync,
1736 rocksdb_db_options->bytes_per_sync,
1737 /* min */ 0L, /* max */ LONG_MAX, 0);
1738
1739 static MYSQL_SYSVAR_UINT64_T(wal_bytes_per_sync,
1740 rocksdb_db_options->wal_bytes_per_sync,
1741 PLUGIN_VAR_RQCMDARG,
1742 "DBOptions::wal_bytes_per_sync for RocksDB",
1743 nullptr, rocksdb_set_wal_bytes_per_sync,
1744 rocksdb_db_options->wal_bytes_per_sync,
1745 /* min */ 0L, /* max */ LONG_MAX, 0);
1746
1747 static MYSQL_SYSVAR_BOOL(
1748 enable_thread_tracking,
1749 *static_cast<bool *>(&rocksdb_db_options->enable_thread_tracking),
1750 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1751 "DBOptions::enable_thread_tracking for RocksDB", nullptr, nullptr, true);
1752
1753 static MYSQL_SYSVAR_LONGLONG(block_cache_size, rocksdb_block_cache_size,
1754 PLUGIN_VAR_RQCMDARG,
1755 "block_cache size for RocksDB",
1756 rocksdb_validate_set_block_cache_size, nullptr,
1757 /* default */ RDB_DEFAULT_BLOCK_CACHE_SIZE,
1758 /* min */ RDB_MIN_BLOCK_CACHE_SIZE,
1759 /* max */ LLONG_MAX,
1760 /* Block size */ RDB_MIN_BLOCK_CACHE_SIZE);
1761
1762 static MYSQL_SYSVAR_LONGLONG(sim_cache_size, rocksdb_sim_cache_size,
1763 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1764 "Simulated cache size for RocksDB", nullptr,
1765 nullptr,
1766 /* default */ 0,
1767 /* min */ 0,
1768 /* max */ LLONG_MAX,
1769 /* Block size */ 0);
1770
1771 static MYSQL_SYSVAR_BOOL(cache_dump, rocksdb_cache_dump,
1772 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1773 "Include RocksDB block cache content in core dump.",
1774 nullptr, nullptr, true);
1775
1776 static MYSQL_SYSVAR_DOUBLE(cache_high_pri_pool_ratio,
1777 rocksdb_cache_high_pri_pool_ratio,
1778 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1779 "Specify the size of block cache high-pri pool",
1780 nullptr, nullptr, /* default */ 0.0, /* min */ 0.0,
1781 /* max */ 1.0, 0);
1782
1783 static MYSQL_SYSVAR_BOOL(
1784 cache_index_and_filter_blocks,
1785 *static_cast<bool *>(&rocksdb_tbl_options->cache_index_and_filter_blocks),
1786 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1787 "BlockBasedTableOptions::cache_index_and_filter_blocks for RocksDB",
1788 nullptr, nullptr, true);
1789
1790 static MYSQL_SYSVAR_BOOL(
1791 cache_index_and_filter_with_high_priority,
1792 *reinterpret_cast<bool *>(
1793 &rocksdb_tbl_options->cache_index_and_filter_blocks_with_high_priority),
1794 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1795 "cache_index_and_filter_blocks_with_high_priority for RocksDB", nullptr,
1796 nullptr, true);
1797
1798 // When pin_l0_filter_and_index_blocks_in_cache is true, RocksDB will use the
1799 // LRU cache, but will always keep the filter & idndex block's handle checked
1800 // out (=won't call ShardedLRUCache::Release), plus the parsed out objects
1801 // the LRU cache will never push flush them out, hence they're pinned.
1802 //
1803 // This fixes the mutex contention between :ShardedLRUCache::Lookup and
1804 // ShardedLRUCache::Release which reduced the QPS ratio (QPS using secondary
1805 // index / QPS using PK).
1806 static MYSQL_SYSVAR_BOOL(
1807 pin_l0_filter_and_index_blocks_in_cache,
1808 *static_cast<bool *>(
1809 &rocksdb_tbl_options->pin_l0_filter_and_index_blocks_in_cache),
1810 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1811 "pin_l0_filter_and_index_blocks_in_cache for RocksDB", nullptr, nullptr,
1812 true);
1813
1814 static MYSQL_SYSVAR_ENUM(index_type, rocksdb_index_type,
1815 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1816 "BlockBasedTableOptions::index_type for RocksDB",
1817 nullptr, nullptr,
1818 (uint64_t)rocksdb_tbl_options->index_type,
1819 &index_type_typelib);
1820
1821 static MYSQL_SYSVAR_BOOL(
1822 no_block_cache, *static_cast<bool *>(&rocksdb_tbl_options->no_block_cache),
1823 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1824 "BlockBasedTableOptions::no_block_cache for RocksDB", nullptr, nullptr,
1825 rocksdb_tbl_options->no_block_cache);
1826
1827 static MYSQL_SYSVAR_UINT64_T(block_size, rocksdb_tbl_options->block_size,
1828 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1829 "BlockBasedTableOptions::block_size for RocksDB",
1830 nullptr, nullptr, rocksdb_tbl_options->block_size,
1831 /* min */ 1024L, /* max */ LONG_MAX, 0);
1832
1833 static MYSQL_SYSVAR_INT(
1834 block_size_deviation, rocksdb_tbl_options->block_size_deviation,
1835 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1836 "BlockBasedTableOptions::block_size_deviation for RocksDB", nullptr,
1837 nullptr, rocksdb_tbl_options->block_size_deviation,
1838 /* min */ 0, /* max */ INT_MAX, 0);
1839
1840 static MYSQL_SYSVAR_INT(
1841 block_restart_interval, rocksdb_tbl_options->block_restart_interval,
1842 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1843 "BlockBasedTableOptions::block_restart_interval for RocksDB", nullptr,
1844 nullptr, rocksdb_tbl_options->block_restart_interval,
1845 /* min */ 1, /* max */ INT_MAX, 0);
1846
1847 static MYSQL_SYSVAR_BOOL(
1848 whole_key_filtering,
1849 *static_cast<bool *>(&rocksdb_tbl_options->whole_key_filtering),
1850 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1851 "BlockBasedTableOptions::whole_key_filtering for RocksDB", nullptr, nullptr,
1852 rocksdb_tbl_options->whole_key_filtering);
1853
1854 static MYSQL_SYSVAR_STR(default_cf_options, rocksdb_default_cf_options,
1855 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1856 "default cf options for RocksDB", nullptr, nullptr,
1857 "block_based_table_factory={cache_index_and_filter_"
1858 "blocks=1;filter_policy=bloomfilter:10:false;whole_key_"
1859 "filtering=1};level_compaction_dynamic_level_bytes="
1860 "true;optimize_filters_for_hits=true;compaction_pri="
1861 "kMinOverlappingRatio;compression=kLZ4Compression;"
1862 "bottommost_compression=kLZ4Compression;");
1863
1864 static MYSQL_SYSVAR_STR(override_cf_options, rocksdb_override_cf_options,
1865 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1866 "option overrides per cf for RocksDB", nullptr, nullptr,
1867 "");
1868
1869 static MYSQL_SYSVAR_STR(update_cf_options, rocksdb_update_cf_options,
1870 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC |
1871 PLUGIN_VAR_NOCMDOPT,
1872 "Option updates per column family for RocksDB",
1873 rocksdb_validate_update_cf_options,
1874 rocksdb_set_update_cf_options, nullptr);
1875
1876 static MYSQL_SYSVAR_BOOL(use_default_sk_cf, rocksdb_use_default_sk_cf,
1877 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1878 "Use default_sk for secondary keys", nullptr, nullptr,
1879 false);
1880
1881 static MYSQL_SYSVAR_BOOL(allow_unsafe_alter, rocksdb_allow_unsafe_alter,
1882 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1883 "Enable crash unsafe INPLACE ADD|DROP partition.",
1884 nullptr, nullptr, false);
1885
1886 static MYSQL_SYSVAR_UINT(flush_log_at_trx_commit,
1887 rocksdb_flush_log_at_trx_commit, PLUGIN_VAR_RQCMDARG,
1888 "Sync on transaction commit. Similar to "
1889 "innodb_flush_log_at_trx_commit. 1: sync on commit, "
1890 "0,2: not sync on commit",
1891 rocksdb_validate_flush_log_at_trx_commit, nullptr,
1892 /* default */ FLUSH_LOG_SYNC,
1893 /* min */ FLUSH_LOG_NEVER,
1894 /* max */ FLUSH_LOG_BACKGROUND, 0);
1895
1896 static MYSQL_THDVAR_BOOL(write_disable_wal,
1897 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1898 "WriteOptions::disableWAL for RocksDB",
1899 rocksdb_check_write_disable_wal, nullptr,
1900 rocksdb::WriteOptions().disableWAL);
1901 static MYSQL_THDVAR_BOOL(write_disable_wal_save, PLUGIN_VAR_INVISIBLE,
1902 "WriteOptions::disableWAL shadow", nullptr, nullptr,
1903 rocksdb::WriteOptions().disableWAL);
1904
1905 static MYSQL_THDVAR_BOOL(
1906 write_ignore_missing_column_families,
1907 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1908 "WriteOptions::ignore_missing_column_families for RocksDB", nullptr,
1909 nullptr, rocksdb::WriteOptions().ignore_missing_column_families);
1910
1911 static MYSQL_THDVAR_BOOL(skip_fill_cache,
1912 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1913 "Skip filling block cache on read requests", nullptr,
1914 nullptr, false);
1915
1916 static MYSQL_THDVAR_BOOL(
1917 unsafe_for_binlog, PLUGIN_VAR_RQCMDARG,
1918 "Allowing statement based binary logging which may break consistency",
1919 nullptr, nullptr, false);
1920
1921 static MYSQL_THDVAR_UINT(records_in_range,
1922 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1923 "Used to override the result of records_in_range(). "
1924 "Set to a positive number to override",
1925 nullptr, nullptr, 0,
1926 /* min */ 0, /* max */ INT_MAX, 0);
1927
1928 static MYSQL_THDVAR_UINT(force_index_records_in_range,
1929 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
1930 "Used to override the result of records_in_range() "
1931 "when FORCE INDEX is used.",
1932 nullptr, nullptr, 0,
1933 /* min */ 0, /* max */ INT_MAX, 0);
1934
1935 static MYSQL_SYSVAR_UINT(
1936 debug_optimizer_n_rows, rocksdb_debug_optimizer_n_rows,
1937 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR,
1938 "Test only to override rocksdb estimates of table size in a memtable",
1939 nullptr, nullptr, 0, /* min */ 0, /* max */ INT_MAX, 0);
1940
1941 static MYSQL_SYSVAR_BOOL(force_compute_memtable_stats,
1942 rocksdb_force_compute_memtable_stats,
1943 PLUGIN_VAR_RQCMDARG,
1944 "Force to always compute memtable stats", nullptr,
1945 nullptr, true);
1946
1947 static MYSQL_SYSVAR_UINT(
1948 force_compute_memtable_stats_cachetime,
1949 rocksdb_force_compute_memtable_stats_cachetime, PLUGIN_VAR_RQCMDARG,
1950 "Time in usecs to cache memtable estimates", nullptr, nullptr,
1951 /* default */ RDB_DEFAULT_FORCE_COMPUTE_MEMTABLE_STATS_CACHETIME,
1952 /* min */ 0, /* max */ INT_MAX, 0);
1953
1954 static MYSQL_SYSVAR_BOOL(
1955 debug_optimizer_no_zero_cardinality,
1956 rocksdb_debug_optimizer_no_zero_cardinality, PLUGIN_VAR_RQCMDARG,
1957 "In case if cardinality is zero, overrides it with some value", nullptr,
1958 nullptr, true);
1959
1960 static MYSQL_SYSVAR_UINT(debug_cardinality_multiplier,
1961 rocksdb_debug_cardinality_multiplier,
1962 PLUGIN_VAR_RQCMDARG,
1963 "Cardinality multiplier used in tests", nullptr,
1964 nullptr, /* default */ 2,
1965 /* min */ 0, /* max */ INT_MAX, 0);
1966
1967 static MYSQL_SYSVAR_STR(compact_cf, rocksdb_compact_cf_name,
1968 PLUGIN_VAR_RQCMDARG, "Compact column family",
1969 rocksdb_compact_column_family,
1970 rocksdb_compact_column_family_stub, "");
1971
1972 static MYSQL_SYSVAR_STR(delete_cf, rocksdb_delete_cf_name, PLUGIN_VAR_RQCMDARG,
1973 "Delete column family", rocksdb_delete_column_family,
1974 rocksdb_delete_column_family_stub, "");
1975
1976 static MYSQL_SYSVAR_STR(create_checkpoint, rocksdb_checkpoint_name,
1977 PLUGIN_VAR_RQCMDARG, "Checkpoint directory",
1978 rocksdb_create_checkpoint_validate,
1979 rocksdb_create_checkpoint_update, "");
1980
1981 static MYSQL_THDVAR_STR(create_temporary_checkpoint,
1982 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC |
1983 PLUGIN_VAR_NOCMDOPT,
1984 "Temporary checkpoint directory",
1985 rocksdb_create_temporary_checkpoint_validate, nullptr,
1986 nullptr);
1987
1988 static MYSQL_SYSVAR_BOOL(signal_drop_index_thread,
1989 rocksdb_signal_drop_index_thread, PLUGIN_VAR_RQCMDARG,
1990 "Wake up drop index thread", nullptr,
1991 rocksdb_drop_index_wakeup_thread, false);
1992
1993 static MYSQL_SYSVAR_BOOL(pause_background_work, rocksdb_pause_background_work,
1994 PLUGIN_VAR_RQCMDARG,
1995 "Disable all rocksdb background operations", nullptr,
1996 rocksdb_set_pause_background_work, false);
1997
1998 static MYSQL_THDVAR_BOOL(disable_file_deletions,
1999 PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_RQCMDARG,
2000 "Prevent file deletions", nullptr,
2001 rocksdb_disable_file_deletions_update, false);
2002
2003 static MYSQL_SYSVAR_BOOL(
2004 enable_ttl, rocksdb_enable_ttl, PLUGIN_VAR_RQCMDARG,
2005 "Enable expired TTL records to be dropped during compaction.", nullptr,
2006 nullptr, true);
2007
2008 static MYSQL_SYSVAR_BOOL(
2009 enable_ttl_read_filtering, rocksdb_enable_ttl_read_filtering,
2010 PLUGIN_VAR_RQCMDARG,
2011 "For tables with TTL, expired records are skipped/filtered out during "
2012 "processing and in query results. Disabling this will allow these records "
2013 "to be seen, but as a result rows may disappear in the middle of "
2014 "transactions as they are dropped during compaction. Use with caution.",
2015 nullptr, nullptr, true);
2016
2017 static MYSQL_SYSVAR_INT(
2018 debug_ttl_rec_ts, rocksdb_debug_ttl_rec_ts, PLUGIN_VAR_RQCMDARG,
2019 "For debugging purposes only. Overrides the TTL of records to "
2020 "now() + debug_ttl_rec_ts. The value can be +/- to simulate "
2021 "a record inserted in the past vs a record inserted in the 'future'. "
2022 "A value of 0 denotes that the variable is not set. This variable is a "
2023 "no-op in non-debug builds.",
2024 nullptr, nullptr, 0, /* min */ -3600, /* max */ 3600, 0);
2025
2026 static MYSQL_SYSVAR_INT(
2027 debug_ttl_snapshot_ts, rocksdb_debug_ttl_snapshot_ts, PLUGIN_VAR_RQCMDARG,
2028 "For debugging purposes only. Sets the snapshot during compaction to "
2029 "now() + debug_set_ttl_snapshot_ts. The value can be +/- to simulate "
2030 "a snapshot in the past vs a snapshot created in the 'future'. "
2031 "A value of 0 denotes that the variable is not set. This variable is a "
2032 "no-op in non-debug builds.",
2033 nullptr, nullptr, 0, /* min */ -3600, /* max */ 3600, 0);
2034
2035 static MYSQL_SYSVAR_INT(
2036 debug_ttl_read_filter_ts, rocksdb_debug_ttl_read_filter_ts,
2037 PLUGIN_VAR_RQCMDARG,
2038 "For debugging purposes only. Overrides the TTL read filtering time to "
2039 "time + debug_ttl_read_filter_ts. A value of 0 denotes that the variable "
2040 "is not set. This variable is a no-op in non-debug builds.",
2041 nullptr, nullptr, 0, /* min */ -3600, /* max */ 3600, 0);
2042
2043 static MYSQL_SYSVAR_BOOL(
2044 debug_ttl_ignore_pk, rocksdb_debug_ttl_ignore_pk, PLUGIN_VAR_RQCMDARG,
2045 "For debugging purposes only. If true, compaction filtering will not occur "
2046 "on PK TTL data. This variable is a no-op in non-debug builds.",
2047 nullptr, nullptr, false);
2048
2049 static MYSQL_SYSVAR_UINT(
2050 max_manual_compactions, rocksdb_max_manual_compactions, PLUGIN_VAR_RQCMDARG,
2051 "Maximum number of pending + ongoing number of manual compactions.",
2052 nullptr, nullptr, /* default */ 10, /* min */ 0, /* max */ UINT_MAX, 0);
2053
2054 static MYSQL_SYSVAR_BOOL(
2055 rollback_on_timeout, rocksdb_rollback_on_timeout, PLUGIN_VAR_OPCMDARG,
2056 "Whether to roll back the complete transaction or a single statement on "
2057 "lock wait timeout (a single statement by default)",
2058 NULL, NULL, false);
2059
2060 static MYSQL_SYSVAR_UINT(
2061 debug_manual_compaction_delay, rocksdb_debug_manual_compaction_delay,
2062 PLUGIN_VAR_RQCMDARG,
2063 "For debugging purposes only. Sleeping specified seconds "
2064 "for simulating long running compactions.",
2065 nullptr, nullptr, 0, /* min */ 0, /* max */ UINT_MAX, 0);
2066
2067 static MYSQL_SYSVAR_BOOL(
2068 reset_stats, rocksdb_reset_stats, PLUGIN_VAR_RQCMDARG,
2069 "Reset the RocksDB internal statistics without restarting the DB.", nullptr,
2070 rocksdb_set_reset_stats, false);
2071
2072 static MYSQL_SYSVAR_BOOL(ignore_unknown_options, rocksdb_ignore_unknown_options,
2073 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
2074 "Enable ignoring unknown options passed to RocksDB",
2075 nullptr, nullptr, true);
2076
2077 /*
2078 TODO(herman) - Both strict_collation_check and strict_collation_exceptions can
2079 be deprecated now that SKs support index lookups for all collations.
2080 */
2081 static MYSQL_SYSVAR_BOOL(strict_collation_check, rocksdb_strict_collation_check,
2082 PLUGIN_VAR_RQCMDARG,
2083 "Enforce case sensitive collation for MyRocks indexes",
2084 nullptr, nullptr, true);
2085
2086 static MYSQL_SYSVAR_STR(strict_collation_exceptions,
2087 rocksdb_strict_collation_exceptions,
2088 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
2089 "Regex that describes set of tables that are excluded "
2090 "from the case sensitive collation enforcement",
2091 nullptr, rocksdb_set_collation_exception_list, "");
2092
2093 static MYSQL_SYSVAR_BOOL(collect_sst_properties, rocksdb_collect_sst_properties,
2094 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
2095 "Enables collecting SST file properties on each flush",
2096 nullptr, nullptr, rocksdb_collect_sst_properties);
2097
2098 static MYSQL_SYSVAR_BOOL(
2099 force_flush_memtable_now, rocksdb_force_flush_memtable_now_var,
2100 PLUGIN_VAR_RQCMDARG,
2101 "Forces memstore flush which may block all write requests so be careful",
2102 rocksdb_force_flush_memtable_now, rocksdb_force_flush_memtable_now_stub,
2103 true);
2104
2105 static MYSQL_SYSVAR_BOOL(
2106 force_flush_memtable_and_lzero_now,
2107 rocksdb_force_flush_memtable_and_lzero_now_var, PLUGIN_VAR_RQCMDARG,
2108 "Acts similar to force_flush_memtable_now, but also compacts all L0 files.",
2109 rocksdb_force_flush_memtable_and_lzero_now,
2110 rocksdb_force_flush_memtable_and_lzero_now_stub, false);
2111
2112 static MYSQL_SYSVAR_BOOL(cancel_manual_compactions,
2113 rocksdb_cancel_manual_compactions_var,
2114 PLUGIN_VAR_RQCMDARG,
2115 "Cancelling all ongoing manual compactions.",
2116 rocksdb_cancel_manual_compactions,
2117 rocksdb_cancel_manual_compactions_stub, false);
2118
2119 static MYSQL_SYSVAR_UINT(
2120 seconds_between_stat_computes, rocksdb_seconds_between_stat_computes,
2121 PLUGIN_VAR_RQCMDARG,
2122 "Sets a number of seconds to wait between optimizer stats recomputation. "
2123 "Only changed indexes will be refreshed.",
2124 nullptr, nullptr, rocksdb_seconds_between_stat_computes,
2125 /* min */ 0L, /* max */ UINT_MAX, 0);
2126
2127 static MYSQL_SYSVAR_LONGLONG(compaction_sequential_deletes,
2128 rocksdb_compaction_sequential_deletes,
2129 PLUGIN_VAR_RQCMDARG,
2130 "RocksDB will trigger compaction for the file if "
2131 "it has more than this number sequential deletes "
2132 "per window",
2133 nullptr, rocksdb_set_compaction_options,
2134 DEFAULT_COMPACTION_SEQUENTIAL_DELETES,
2135 /* min */ 0L,
2136 /* max */ MAX_COMPACTION_SEQUENTIAL_DELETES, 0);
2137
2138 static MYSQL_SYSVAR_LONGLONG(
2139 compaction_sequential_deletes_window,
2140 rocksdb_compaction_sequential_deletes_window, PLUGIN_VAR_RQCMDARG,
2141 "Size of the window for counting rocksdb_compaction_sequential_deletes",
2142 nullptr, rocksdb_set_compaction_options,
2143 DEFAULT_COMPACTION_SEQUENTIAL_DELETES_WINDOW,
2144 /* min */ 0L, /* max */ MAX_COMPACTION_SEQUENTIAL_DELETES_WINDOW, 0);
2145
2146 static MYSQL_SYSVAR_LONGLONG(
2147 compaction_sequential_deletes_file_size,
2148 rocksdb_compaction_sequential_deletes_file_size, PLUGIN_VAR_RQCMDARG,
2149 "Minimum file size required for compaction_sequential_deletes", nullptr,
2150 rocksdb_set_compaction_options, 0L,
2151 /* min */ -1L, /* max */ LLONG_MAX, 0);
2152
2153 static MYSQL_SYSVAR_BOOL(
2154 compaction_sequential_deletes_count_sd,
2155 rocksdb_compaction_sequential_deletes_count_sd, PLUGIN_VAR_RQCMDARG,
2156 "Counting SingleDelete as rocksdb_compaction_sequential_deletes", nullptr,
2157 nullptr, rocksdb_compaction_sequential_deletes_count_sd);
2158
2159 static MYSQL_SYSVAR_BOOL(
2160 print_snapshot_conflict_queries, rocksdb_print_snapshot_conflict_queries,
2161 PLUGIN_VAR_RQCMDARG,
2162 "Logging queries that got snapshot conflict errors into *.err log", nullptr,
2163 nullptr, rocksdb_print_snapshot_conflict_queries);
2164
2165 static MYSQL_THDVAR_INT(checksums_pct,
2166 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
2167 "How many percentages of rows to be checksummed",
2168 nullptr, nullptr, RDB_MAX_CHECKSUMS_PCT,
2169 /* min */ 0, /* max */ RDB_MAX_CHECKSUMS_PCT, 0);
2170
2171 static MYSQL_THDVAR_BOOL(store_row_debug_checksums,
2172 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
2173 "Include checksums when writing index/table records",
2174 nullptr, nullptr, false /* default value */);
2175
2176 static MYSQL_THDVAR_BOOL(verify_row_debug_checksums,
2177 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
2178 "Verify checksums when reading index/table records",
2179 nullptr, nullptr, false /* default value */);
2180
2181 static MYSQL_THDVAR_BOOL(master_skip_tx_api,
2182 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_HINTUPDATEABLE,
2183 "Skipping holding any lock on row access. "
2184 "Not effective on slave.",
2185 nullptr, nullptr, false);
2186
2187 #if defined(ROCKSDB_INCLUDE_VALIDATE_TABLES) && ROCKSDB_INCLUDE_VALIDATE_TABLES
2188 static MYSQL_SYSVAR_UINT(
2189 validate_tables, rocksdb_validate_tables,
2190 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
2191 "Verify all DD tables match all RocksDB tables (0 means no verification, "
2192 "1 means verify and fail on error, and 2 means verify but continue",
2193 nullptr, nullptr, 1 /* default value */, 0 /* min value */,
2194 2 /* max value */, 0);
2195 #endif // defined(ROCKSDB_INCLUDE_VALIDATE_TABLES) &&
2196 // ROCKSDB_INCLUDE_VALIDATE_TABLES
2197
2198 static MYSQL_SYSVAR_STR(datadir, rocksdb_datadir,
2199 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
2200 "RocksDB data directory", nullptr, nullptr,
2201 "./.rocksdb");
2202
2203 static MYSQL_SYSVAR_STR(fs_uri, rocksdb_fs_uri,
2204 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
2205 "Custom filesystem URI", nullptr, nullptr, nullptr);
2206
2207 static MYSQL_SYSVAR_UINT(
2208 table_stats_sampling_pct, rocksdb_table_stats_sampling_pct,
2209 PLUGIN_VAR_RQCMDARG,
2210 "Percentage of entries to sample when collecting statistics about table "
2211 "properties. Specify either 0 to sample everything or percentage "
2212 "[" STRINGIFY_ARG(RDB_TBL_STATS_SAMPLE_PCT_MIN) ".." STRINGIFY_ARG(
2213 RDB_TBL_STATS_SAMPLE_PCT_MAX) "]. "
2214 "By default " STRINGIFY_ARG(
2215 RDB_DEFAULT_TBL_STATS_SAMPLE_PCT) "% "
2216 "of"
2217 " e"
2218 "nt"
2219 "ri"
2220 "es"
2221 " a"
2222 "re"
2223 " "
2224 "sa"
2225 "mp"
2226 "le"
2227 "d"
2228 ".",
2229 nullptr, rocksdb_set_table_stats_sampling_pct, /* default */
2230 RDB_DEFAULT_TBL_STATS_SAMPLE_PCT, /* everything */ 0,
2231 /* max */ RDB_TBL_STATS_SAMPLE_PCT_MAX, 0);
2232
2233 static MYSQL_SYSVAR_UINT(table_stats_recalc_threshold_pct,
2234 rocksdb_table_stats_recalc_threshold_pct,
2235 PLUGIN_VAR_RQCMDARG,
2236 "Percentage of number of modified rows over total "
2237 "number of rows to trigger stats recalculation",
2238 nullptr, nullptr, /* default */
2239 rocksdb_table_stats_recalc_threshold_pct,
2240 /* everything */ 0,
2241 /* max */ RDB_TBL_STATS_RECALC_THRESHOLD_PCT_MAX, 0);
2242
2243 static MYSQL_SYSVAR_ULONGLONG(
2244 table_stats_recalc_threshold_count,
2245 rocksdb_table_stats_recalc_threshold_count, PLUGIN_VAR_RQCMDARG,
2246 "Number of modified rows to trigger stats recalculation", nullptr,
2247 nullptr, /* default */
2248 rocksdb_table_stats_recalc_threshold_count,
2249 /* everything */ 0,
2250 /* max */ UINT64_MAX, 0);
2251
2252 static MYSQL_SYSVAR_INT(
2253 table_stats_background_thread_nice_value,
2254 rocksdb_table_stats_background_thread_nice_value, PLUGIN_VAR_RQCMDARG,
2255 "nice value for index stats", rocksdb_index_stats_thread_renice, nullptr,
2256 /* default */ rocksdb_table_stats_background_thread_nice_value,
2257 /* min */ THREAD_PRIO_MIN, /* max */ THREAD_PRIO_MAX, 0);
2258
2259 static MYSQL_SYSVAR_ULONGLONG(
2260 table_stats_max_num_rows_scanned, rocksdb_table_stats_max_num_rows_scanned,
2261 PLUGIN_VAR_RQCMDARG,
2262 "The maximum number of rows to scan in table scan based "
2263 "cardinality calculation",
2264 nullptr, nullptr, /* default */
2265 0, /* everything */ 0,
2266 /* max */ UINT64_MAX, 0);
2267
2268 static MYSQL_SYSVAR_UINT(
2269 stats_recalc_rate, rocksdb_stats_recalc_rate, PLUGIN_VAR_RQCMDARG,
2270 "The number of indexes per second to recalculate statistics for. 0 to "
2271 "disable background recalculation.",
2272 nullptr, nullptr, 0 /* default value */, 0 /* min value */,
2273 UINT_MAX /* max value */, 0);
2274
2275 static MYSQL_SYSVAR_BOOL(table_stats_use_table_scan,
2276 rocksdb_table_stats_use_table_scan,
2277 PLUGIN_VAR_RQCMDARG,
2278 "Enable table scan based index calculation.", nullptr,
2279 rocksdb_update_table_stats_use_table_scan,
2280 rocksdb_table_stats_use_table_scan);
2281
2282 static MYSQL_SYSVAR_BOOL(
2283 large_prefix, rocksdb_large_prefix, PLUGIN_VAR_RQCMDARG,
2284 "Support large index prefix length of 3072 bytes. If off, the maximum "
2285 "index prefix length is 767.",
2286 nullptr, nullptr, true);
2287
2288 static MYSQL_SYSVAR_BOOL(
2289 allow_to_start_after_corruption, rocksdb_allow_to_start_after_corruption,
2290 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
2291 "Allow server to start successfully when RocksDB corruption is detected.",
2292 nullptr, nullptr, false);
2293
2294 static MYSQL_SYSVAR_BOOL(error_on_suboptimal_collation,
2295 rocksdb_error_on_suboptimal_collation,
2296 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
2297 "Raise an error instead of warning if a sub-optimal "
2298 "collation is used",
2299 nullptr, nullptr, false);
2300
2301 static MYSQL_SYSVAR_BOOL(
2302 no_create_column_family, rocksdb_no_create_column_family,
2303 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
2304 "Do not allow creation of new Column Families through index comments.",
2305 nullptr, nullptr, false);
2306
2307 static MYSQL_SYSVAR_BOOL(
2308 enable_insert_with_update_caching,
2309 rocksdb_enable_insert_with_update_caching, PLUGIN_VAR_OPCMDARG,
2310 "Whether to enable optimization where we cache the read from a failed "
2311 "insertion attempt in INSERT ON DUPLICATE KEY UPDATE",
2312 nullptr, nullptr, true);
2313
2314 static MYSQL_SYSVAR_STR(
2315 trace_block_cache_access, rocksdb_block_cache_trace_options_str,
2316 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
2317 "Block cache trace option string. The format is "
2318 "sampling_frequency:max_trace_file_size:trace_file_name. "
2319 "sampling_frequency and max_trace_file_size are positive integers. The "
2320 "block accesses are saved to the "
2321 "rocksdb_datadir/block_cache_traces/trace_file_name.",
2322 rocksdb_trace_block_cache_access, nullptr, "");
2323
2324 static MYSQL_SYSVAR_STR(
2325 trace_queries, rocksdb_trace_options_str,
2326 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
2327 "Trace option string. The format is "
2328 "sampling_frequency:max_trace_file_size:trace_file_name. "
2329 "sampling_frequency and max_trace_file_size are positive integers. The "
2330 "queries are saved to the "
2331 "rocksdb_datadir/queries_traces/trace_file_name.",
2332 rocksdb_trace_queries, nullptr, "");
2333
2334 static MYSQL_SYSVAR_ULONGLONG(
2335 max_compaction_history, rocksdb_max_compaction_history, PLUGIN_VAR_OPCMDARG,
2336 "Track history for at most this many completed compactions. "
2337 "The history is in the INFORMATION_SCHEMA.ROCKSDB_COMPACTION_HISTORY "
2338 "table.",
2339 nullptr, rocksdb_max_compaction_history_update,
2340 RDB_DEFAULT_MAX_COMPACTION_HISTORY, 0ULL /* min */, UINT64_MAX /* max */,
2341 0 /* blk */);
2342
2343 static MYSQL_SYSVAR_BOOL(skip_locks_if_skip_unique_check,
2344 rocksdb_skip_locks_if_skip_unique_check,
2345 PLUGIN_VAR_RQCMDARG,
2346 "Skip row locking when unique checks are disabled.",
2347 nullptr, nullptr, false);
2348
2349 static MYSQL_SYSVAR_BOOL(
2350 alter_column_default_inplace, rocksdb_alter_column_default_inplace,
2351 PLUGIN_VAR_RQCMDARG,
2352 "Allow inplace alter for alter column default operation", nullptr, nullptr,
2353 true);
2354
2355 static MYSQL_THDVAR_ULONGLONG(
2356 partial_index_sort_max_mem, PLUGIN_VAR_RQCMDARG,
2357 "Maximum memory to use when sorting an unmaterialized group for partial "
2358 "indexes. 0 means no limit.",
2359 nullptr, nullptr,
2360 /* default */ 0, /* min */ 0, /* max */ SIZE_T_MAX, 1);
2361
2362 static MYSQL_SYSVAR_BOOL(instant_ddl, rocksdb_instant_ddl, PLUGIN_VAR_RQCMDARG,
2363 "Allow instant ddl during alter table", nullptr,
2364 nullptr, false);
2365
2366 static MYSQL_SYSVAR_BOOL(enable_tmp_table, rocksdb_enable_tmp_table,
2367 PLUGIN_VAR_READONLY, "Allow rocksdb tmp tables",
2368 nullptr, nullptr, false);
2369
2370 static const int ROCKSDB_ASSUMED_KEY_VALUE_DISK_SIZE = 100;
2371
2372 static struct SYS_VAR *rocksdb_system_variables[] = {
2373 MYSQL_SYSVAR(lock_wait_timeout),
2374 MYSQL_SYSVAR(deadlock_detect),
2375 MYSQL_SYSVAR(deadlock_detect_depth),
2376 MYSQL_SYSVAR(commit_time_batch_for_recovery),
2377 MYSQL_SYSVAR(max_row_locks),
2378 MYSQL_SYSVAR(write_batch_max_bytes),
2379 MYSQL_SYSVAR(write_batch_flush_threshold),
2380 MYSQL_SYSVAR(lock_scanned_rows),
2381 MYSQL_SYSVAR(bulk_load),
2382 MYSQL_SYSVAR(bulk_load_allow_sk),
2383 MYSQL_SYSVAR(bulk_load_allow_unsorted),
2384 MYSQL_SYSVAR(trace_sst_api),
2385 MYSQL_SYSVAR(commit_in_the_middle),
2386 MYSQL_SYSVAR(blind_delete_primary_key),
2387 MYSQL_SYSVAR(enable_iterate_bounds),
2388 #if defined(ROCKSDB_INCLUDE_RFR) && ROCKSDB_INCLUDE_RFR
2389 MYSQL_SYSVAR(read_free_rpl_tables),
2390 MYSQL_SYSVAR(read_free_rpl),
2391 #endif // defined(ROCKSDB_INCLUDE_RFR) && ROCKSDB_INCLUDE_RFR
2392 MYSQL_SYSVAR(rpl_skip_tx_api),
2393 MYSQL_SYSVAR(bulk_load_size),
2394 MYSQL_SYSVAR(bulk_load_partial_index),
2395 MYSQL_SYSVAR(merge_buf_size),
2396 MYSQL_SYSVAR(enable_bulk_load_api),
2397 MYSQL_SYSVAR(enable_pipelined_write),
2398 MYSQL_SYSVAR(enable_remove_orphaned_dropped_cfs),
2399 MYSQL_SYSVAR(tmpdir),
2400 MYSQL_SYSVAR(merge_combine_read_size),
2401 MYSQL_SYSVAR(merge_tmp_file_removal_delay_ms),
2402 MYSQL_SYSVAR(skip_bloom_filter_on_read),
2403
2404 MYSQL_SYSVAR(create_if_missing),
2405 MYSQL_SYSVAR(concurrent_prepare),
2406 MYSQL_SYSVAR(two_write_queues),
2407 MYSQL_SYSVAR(manual_wal_flush),
2408 MYSQL_SYSVAR(write_policy),
2409 MYSQL_SYSVAR(create_missing_column_families),
2410 MYSQL_SYSVAR(error_if_exists),
2411 MYSQL_SYSVAR(paranoid_checks),
2412 MYSQL_SYSVAR(rate_limiter_bytes_per_sec),
2413 MYSQL_SYSVAR(sst_mgr_rate_bytes_per_sec),
2414 MYSQL_SYSVAR(delayed_write_rate),
2415 MYSQL_SYSVAR(max_latest_deadlocks),
2416 MYSQL_SYSVAR(info_log_level),
2417 MYSQL_SYSVAR(max_open_files),
2418 MYSQL_SYSVAR(max_total_wal_size),
2419 MYSQL_SYSVAR(use_fsync),
2420 MYSQL_SYSVAR(wal_dir),
2421 MYSQL_SYSVAR(persistent_cache_path),
2422 MYSQL_SYSVAR(persistent_cache_size_mb),
2423 MYSQL_SYSVAR(wsenv_path),
2424 MYSQL_SYSVAR(fault_injection_options),
2425 MYSQL_SYSVAR(delete_obsolete_files_period_micros),
2426 MYSQL_SYSVAR(max_background_jobs),
2427 MYSQL_SYSVAR(max_background_flushes),
2428 MYSQL_SYSVAR(max_background_compactions),
2429 MYSQL_SYSVAR(max_bottom_pri_background_compactions),
2430 MYSQL_SYSVAR(max_log_file_size),
2431 MYSQL_SYSVAR(max_subcompactions),
2432 MYSQL_SYSVAR(log_file_time_to_roll),
2433 MYSQL_SYSVAR(keep_log_file_num),
2434 MYSQL_SYSVAR(max_manifest_file_size),
2435 MYSQL_SYSVAR(table_cache_numshardbits),
2436 MYSQL_SYSVAR(wal_ttl_seconds),
2437 MYSQL_SYSVAR(wal_size_limit_mb),
2438 MYSQL_SYSVAR(manifest_preallocation_size),
2439 MYSQL_SYSVAR(use_direct_reads),
2440 MYSQL_SYSVAR(use_direct_io_for_flush_and_compaction),
2441 MYSQL_SYSVAR(allow_mmap_reads),
2442 MYSQL_SYSVAR(allow_mmap_writes),
2443 MYSQL_SYSVAR(is_fd_close_on_exec),
2444 MYSQL_SYSVAR(stats_dump_period_sec),
2445 MYSQL_SYSVAR(advise_random_on_open),
2446 MYSQL_SYSVAR(db_write_buffer_size),
2447 MYSQL_SYSVAR(use_adaptive_mutex),
2448 MYSQL_SYSVAR(bytes_per_sync),
2449 MYSQL_SYSVAR(wal_bytes_per_sync),
2450 MYSQL_SYSVAR(enable_thread_tracking),
2451 MYSQL_SYSVAR(perf_context_level),
2452 MYSQL_SYSVAR(wal_recovery_mode),
2453 MYSQL_SYSVAR(track_and_verify_wals_in_manifest),
2454 MYSQL_SYSVAR(stats_level),
2455 MYSQL_SYSVAR(access_hint_on_compaction_start),
2456 MYSQL_SYSVAR(compaction_readahead_size),
2457 MYSQL_SYSVAR(allow_concurrent_memtable_write),
2458 MYSQL_SYSVAR(enable_write_thread_adaptive_yield),
2459
2460 MYSQL_SYSVAR(block_cache_size),
2461 MYSQL_SYSVAR(sim_cache_size),
2462 MYSQL_SYSVAR(cache_high_pri_pool_ratio),
2463 MYSQL_SYSVAR(cache_dump),
2464 MYSQL_SYSVAR(cache_index_and_filter_blocks),
2465 MYSQL_SYSVAR(cache_index_and_filter_with_high_priority),
2466 MYSQL_SYSVAR(pin_l0_filter_and_index_blocks_in_cache),
2467 MYSQL_SYSVAR(index_type),
2468 MYSQL_SYSVAR(no_block_cache),
2469 MYSQL_SYSVAR(block_size),
2470 MYSQL_SYSVAR(block_size_deviation),
2471 MYSQL_SYSVAR(block_restart_interval),
2472 MYSQL_SYSVAR(whole_key_filtering),
2473
2474 MYSQL_SYSVAR(default_cf_options),
2475 MYSQL_SYSVAR(override_cf_options),
2476 MYSQL_SYSVAR(update_cf_options),
2477 MYSQL_SYSVAR(use_default_sk_cf),
2478 MYSQL_SYSVAR(allow_unsafe_alter),
2479
2480 MYSQL_SYSVAR(flush_log_at_trx_commit),
2481 MYSQL_SYSVAR(write_disable_wal),
2482 MYSQL_SYSVAR(write_disable_wal_save),
2483 MYSQL_SYSVAR(write_ignore_missing_column_families),
2484
2485 MYSQL_SYSVAR(skip_fill_cache),
2486 MYSQL_SYSVAR(unsafe_for_binlog),
2487
2488 MYSQL_SYSVAR(records_in_range),
2489 MYSQL_SYSVAR(force_index_records_in_range),
2490 MYSQL_SYSVAR(debug_optimizer_n_rows),
2491 MYSQL_SYSVAR(force_compute_memtable_stats),
2492 MYSQL_SYSVAR(force_compute_memtable_stats_cachetime),
2493 MYSQL_SYSVAR(debug_optimizer_no_zero_cardinality),
2494 MYSQL_SYSVAR(debug_cardinality_multiplier),
2495
2496 MYSQL_SYSVAR(compact_cf),
2497 MYSQL_SYSVAR(delete_cf),
2498 MYSQL_SYSVAR(signal_drop_index_thread),
2499 MYSQL_SYSVAR(pause_background_work),
2500 MYSQL_SYSVAR(ignore_unknown_options),
2501 MYSQL_SYSVAR(strict_collation_check),
2502 MYSQL_SYSVAR(strict_collation_exceptions),
2503 MYSQL_SYSVAR(collect_sst_properties),
2504 MYSQL_SYSVAR(force_flush_memtable_now),
2505 MYSQL_SYSVAR(force_flush_memtable_and_lzero_now),
2506 MYSQL_SYSVAR(cancel_manual_compactions),
2507 MYSQL_SYSVAR(enable_ttl),
2508 MYSQL_SYSVAR(enable_ttl_read_filtering),
2509 MYSQL_SYSVAR(debug_ttl_rec_ts),
2510 MYSQL_SYSVAR(debug_ttl_snapshot_ts),
2511 MYSQL_SYSVAR(debug_ttl_read_filter_ts),
2512 MYSQL_SYSVAR(debug_ttl_ignore_pk),
2513 MYSQL_SYSVAR(reset_stats),
2514 MYSQL_SYSVAR(seconds_between_stat_computes),
2515
2516 MYSQL_SYSVAR(compaction_sequential_deletes),
2517 MYSQL_SYSVAR(compaction_sequential_deletes_window),
2518 MYSQL_SYSVAR(compaction_sequential_deletes_file_size),
2519 MYSQL_SYSVAR(compaction_sequential_deletes_count_sd),
2520 MYSQL_SYSVAR(print_snapshot_conflict_queries),
2521
2522 MYSQL_SYSVAR(datadir),
2523 MYSQL_SYSVAR(fs_uri),
2524 MYSQL_SYSVAR(create_checkpoint),
2525 MYSQL_SYSVAR(create_temporary_checkpoint),
2526 MYSQL_SYSVAR(disable_file_deletions),
2527
2528 MYSQL_SYSVAR(checksums_pct),
2529 MYSQL_SYSVAR(store_row_debug_checksums),
2530 MYSQL_SYSVAR(verify_row_debug_checksums),
2531 MYSQL_SYSVAR(master_skip_tx_api),
2532
2533 #if defined(ROCKSDB_INCLUDE_VALIDATE_TABLES) && ROCKSDB_INCLUDE_VALIDATE_TABLES
2534 MYSQL_SYSVAR(validate_tables),
2535 #endif // defined(ROCKSDB_INCLUDE_VALIDATE_TABLES) &&
2536 // ROCKSDB_INCLUDE_VALIDATE_TABLES
2537 MYSQL_SYSVAR(table_stats_sampling_pct),
2538 MYSQL_SYSVAR(table_stats_recalc_threshold_pct),
2539 MYSQL_SYSVAR(table_stats_recalc_threshold_count),
2540 MYSQL_SYSVAR(table_stats_max_num_rows_scanned),
2541 MYSQL_SYSVAR(table_stats_use_table_scan),
2542 MYSQL_SYSVAR(table_stats_background_thread_nice_value),
2543
2544 MYSQL_SYSVAR(large_prefix),
2545 MYSQL_SYSVAR(allow_to_start_after_corruption),
2546 MYSQL_SYSVAR(error_on_suboptimal_collation),
2547 MYSQL_SYSVAR(no_create_column_family),
2548 MYSQL_SYSVAR(stats_recalc_rate),
2549 MYSQL_SYSVAR(debug_manual_compaction_delay),
2550 MYSQL_SYSVAR(max_manual_compactions),
2551 MYSQL_SYSVAR(manual_compaction_threads),
2552 MYSQL_SYSVAR(manual_compaction_bottommost_level),
2553 MYSQL_SYSVAR(rollback_on_timeout),
2554
2555 MYSQL_SYSVAR(enable_insert_with_update_caching),
2556 MYSQL_SYSVAR(trace_block_cache_access),
2557 MYSQL_SYSVAR(trace_queries),
2558 MYSQL_SYSVAR(max_compaction_history),
2559 MYSQL_SYSVAR(skip_locks_if_skip_unique_check),
2560 MYSQL_SYSVAR(alter_column_default_inplace),
2561 MYSQL_SYSVAR(partial_index_sort_max_mem),
2562 MYSQL_SYSVAR(instant_ddl),
2563 MYSQL_SYSVAR(enable_tmp_table),
2564 nullptr};
2565
2566 48154 static bool is_tmp_table(const std::string &tablename) {
2567
2/2
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 47968 times.
48154 if (tablename.find(TMP_SCHEMA_NAME) == 0) {
2568 // should land this case only if rocksdb_enable_tmp_table is enabled.
2569
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 186 times.
186 assert(rocksdb_enable_tmp_table);
2570 186 return true;
2571 } else {
2572 47968 return false;
2573 }
2574 }
2575
2576 1227 static int rocksdb_compact_column_family(THD *const thd,
2577 struct SYS_VAR *const var,
2578 void *const var_ptr,
2579 struct st_mysql_value *const value) {
2580 char buff[STRING_BUFFER_USUAL_SIZE];
2581 1227 int len = sizeof(buff);
2582
2583
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1227 times.
1227 assert(value != nullptr);
2584
2585
2/4
✓ Branch 0 taken 1227 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1227 times.
✗ Branch 3 not taken.
1227 if (const char *const cf = value->val_str(value, buff, &len)) {
2586
5/8
✓ Branch 0 taken 1227 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1224 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
1227 DBUG_EXECUTE_IF("rocksdb_compact_column_family", {
2587 static constexpr char act[] =
2588 "now signal ready_to_mark_cf_dropped_in_compact_column_family "
2589 "wait_for mark_cf_dropped_done_in_compact_column_family";
2590 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
2591 });
2592
2593
1/2
✓ Branch 0 taken 1227 times.
✗ Branch 1 not taken.
1227 std::string cf_name = std::string(cf);
2594 // use rocksdb_compact_cf="" or "default" to compact default CF
2595
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1226 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1227 if (cf_name.empty()) cf_name = DEFAULT_CF_NAME;
2596
2597
1/2
✓ Branch 0 taken 1227 times.
✗ Branch 1 not taken.
1227 auto cfh = cf_manager.get_cf(cf_name);
2598
5/6
✓ Branch 0 taken 1213 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 1213 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1213 times.
✓ Branch 5 taken 14 times.
1227 if (cfh != nullptr && rdb != nullptr) {
2599 rocksdb::BottommostLevelCompaction bottommost_level_compaction =
2600
1/2
✓ Branch 0 taken 1213 times.
✗ Branch 1 not taken.
1213 (rocksdb::BottommostLevelCompaction)THDVAR(
2601 thd, manual_compaction_bottommost_level);
2602
2603
1/2
✓ Branch 0 taken 1213 times.
✗ Branch 1 not taken.
1213 int mc_id = rdb_mc_thread.request_manual_compaction(
2604
1/2
✓ Branch 0 taken 1213 times.
✗ Branch 1 not taken.
1213 cfh, nullptr, nullptr, THDVAR(thd, manual_compaction_threads),
2605 1213 bottommost_level_compaction);
2606
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1207 times.
1213 if (mc_id == -1) {
2607
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 my_error(ER_INTERNAL_ERROR, MYF(0),
2608 "Can't schedule more manual compactions. "
2609 "Increase rocksdb_max_manual_compactions or stop issuing "
2610 "more manual compactions.");
2611 24 return HA_EXIT_FAILURE;
2612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1207 times.
1207 } else if (mc_id < 0) {
2613 return HA_EXIT_FAILURE;
2614 }
2615
2616 auto grd =
2617
1/2
✓ Branch 0 taken 1207 times.
✗ Branch 1 not taken.
2414 create_scope_guard([&]() { rdb_mc_thread.set_client_done(mc_id); });
2618 // NO_LINT_DEBUG
2619
9/18
✓ Branch 0 taken 1207 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1207 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1207 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1207 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1207 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1207 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1207 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1207 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1207 times.
✗ Branch 17 not taken.
1207 LogPluginErrMsg(INFORMATION_LEVEL, 0,
2620 "Manual compaction of column family: %s\n", cf);
2621 // Checking thd state every short cycle (100ms). This is for allowing to
2622 // exiting this function without waiting for CompactRange to finish.
2623 Rdb_manual_compaction_thread::Manual_compaction_request::mc_state
2624 mc_status;
2625 do {
2626
1/2
✓ Branch 0 taken 11565 times.
✗ Branch 1 not taken.
11566 my_sleep(100000);
2627
1/2
✓ Branch 0 taken 11566 times.
✗ Branch 1 not taken.
11565 mc_status = rdb_mc_thread.manual_compaction_state(mc_id);
2628
6/6
✓ Branch 0 taken 11554 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 4237 times.
✓ Branch 3 taken 7317 times.
✓ Branch 4 taken 10359 times.
✓ Branch 5 taken 1207 times.
15803 } while (!thd->killed &&
2629 (mc_status == Rdb_manual_compaction_thread::
2630
2/2
✓ Branch 0 taken 3042 times.
✓ Branch 1 taken 1195 times.
4237 Manual_compaction_request::PENDING ||
2631 mc_status == Rdb_manual_compaction_thread::
2632 Manual_compaction_request::RUNNING));
2633
2634 1207 bool mc_timeout = false;
2635
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1195 times.
1207 if (thd->killed) {
2636 // Cancelling pending or running manual compaction with 60s timeout
2637
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 mc_timeout = rdb_mc_thread.cancel_manual_compaction_request(mc_id, 600);
2638 }
2639
2640
1/2
✓ Branch 0 taken 1207 times.
✗ Branch 1 not taken.
1207 mc_status = rdb_mc_thread.manual_compaction_state(mc_id);
2641
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 1189 times.
1207 if (mc_status !=
2642 Rdb_manual_compaction_thread::Manual_compaction_request::SUCCESS) {
2643
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 std::string msg = "Manual Compaction Failed. Reason: ";
2644
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 if (thd->killed) {
2645
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 msg += "Cancelled by client.";
2646
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 } else if (mc_status == Rdb_manual_compaction_thread::
2647 Manual_compaction_request::CANCEL) {
2648
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 msg += "Cancelled by server.";
2649 } else {
2650 msg += "General failures.";
2651 }
2652
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
18 if (mc_timeout) {
2653
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 msg += " (timeout)";
2654 }
2655
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 my_error(ER_INTERNAL_ERROR, MYF(0), msg.c_str());
2656 18 return HA_EXIT_FAILURE;
2657 18 }
2658
2/2
✓ Branch 0 taken 1189 times.
✓ Branch 1 taken 18 times.
1207 }
2659
4/4
✓ Branch 0 taken 1203 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 1203 times.
✓ Branch 3 taken 24 times.
1251 }
2660 1203 return HA_EXIT_SUCCESS;
2661 }
2662
2663 /*
2664 * Serializes an xid to a string so that it can
2665 * be used as a rocksdb transaction name
2666 */
2667 3613302 static std::string rdb_xid_to_string(const XID &src) {
2668
3/4
✓ Branch 0 taken 3613475 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3613535 times.
✓ Branch 3 taken 21 times.
3613302 assert(src.get_gtrid_length() >= 0 &&
2669 src.get_gtrid_length() <= MAXGTRIDSIZE);
2670
2/4
✓ Branch 0 taken 3613687 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3613923 times.
✗ Branch 3 not taken.
3613535 assert(src.get_bqual_length() >= 0 &&
2671 src.get_bqual_length() <= MAXBQUALSIZE);
2672
2673 3613923 std::string buf;
2674
1/2
✓ Branch 0 taken 3613801 times.
✗ Branch 1 not taken.
3613562 buf.reserve(RDB_XIDHDR_LEN + src.get_gtrid_length() + src.get_bqual_length());
2675
2676 /*
2677 * expand formatID to fill 8 bytes if it doesn't already
2678 * then reinterpret bit pattern as unsigned and store in network order
2679 */
2680 uchar fidbuf[RDB_FORMATID_SZ];
2681 3613801 int64 signed_fid8 = src.get_format_id();
2682 3613682 const uint64 raw_fid8 = *reinterpret_cast<uint64 *>(&signed_fid8);
2683 3613682 rdb_netbuf_store_uint64(fidbuf, raw_fid8);
2684
1/2
✓ Branch 0 taken 3613492 times.
✗ Branch 1 not taken.
3613326 buf.append(reinterpret_cast<const char *>(fidbuf), RDB_FORMATID_SZ);
2685
2686
1/2
✓ Branch 0 taken 3613454 times.
✗ Branch 1 not taken.
3613492 buf.push_back(src.get_gtrid_length());
2687
1/2
✓ Branch 0 taken 3613889 times.
✗ Branch 1 not taken.
3613454 buf.push_back(src.get_bqual_length());
2688
1/2
✓ Branch 0 taken 3613750 times.
✗ Branch 1 not taken.
3613489 buf.append(src.get_data(),
2689 3613889 (src.get_gtrid_length()) + (src.get_bqual_length()));
2690 7227500 return buf;
2691 }
2692
2693 ///////////////////////////////////////////////////////////////////////////////////////////
2694
2695 /*
2696 Drop index thread's control
2697 */
2698
2699 25 static void rocksdb_drop_index_wakeup_thread(
2700 my_core::THD *const thd MY_ATTRIBUTE((__unused__)),
2701 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
2702 void *const var_ptr MY_ATTRIBUTE((__unused__)), const void *const save) {
2703
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 5 times.
25 if (*static_cast<const bool *>(save)) {
2704 20 rdb_drop_idx_thread.signal();
2705 }
2706 25 }
2707
2708 12024589 static inline uint32_t rocksdb_perf_context_level(THD *const thd) {
2709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12024589 times.
12024589 assert(thd != nullptr);
2710
2711 12024589 const int session_perf_context_level = THDVAR(thd, perf_context_level);
2712
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 12024424 times.
12024742 if (session_perf_context_level > rocksdb::PerfLevel::kUninitialized) {
2713 318 return session_perf_context_level;
2714 }
2715
2716 /*
2717 Fallback to global thdvar, if session specific one was not set to a valid
2718 value.
2719 */
2720
2721 12024424 const int global_perf_context_level = THDVAR(nullptr, perf_context_level);
2722
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 12024490 times.
12024571 if (global_perf_context_level > rocksdb::PerfLevel::kUninitialized) {
2723 81 return global_perf_context_level;
2724 }
2725
2726 12024490 return rocksdb::PerfLevel::kDisable;
2727 }
2728
2729 /*
2730 Very short (functor-like) interface to be passed to
2731 Rdb_transaction::walk_tx_list()
2732 */
2733
2734 interface Rdb_tx_list_walker {
2735 232 virtual ~Rdb_tx_list_walker() {}
2736 virtual void process_tran(const Rdb_transaction *const) = 0;
2737 };
2738
2739 /*
2740 This is a helper class that is passed to RocksDB to get notifications when
2741 a snapshot gets created.
2742 */
2743
2744 class Rdb_snapshot_notifier : public rocksdb::TransactionNotifier {
2745 Rdb_transaction *m_owning_tx;
2746
2747 void SnapshotCreated(const rocksdb::Snapshot *snapshot) override;
2748
2749 public:
2750 Rdb_snapshot_notifier(const Rdb_snapshot_notifier &) = delete;
2751 Rdb_snapshot_notifier &operator=(const Rdb_snapshot_notifier &) = delete;
2752
2753 2567 explicit Rdb_snapshot_notifier(Rdb_transaction *const owning_tx)
2754 2567 : m_owning_tx(owning_tx) {}
2755
2756 // If the owning Rdb_transaction gets destructed we need to not reference
2757 // it anymore.
2758 2527 void detach() { m_owning_tx = nullptr; }
2759 };
2760
2761 /* This is the base class for transactions when interacting with rocksdb.
2762 */
2763 class Rdb_transaction {
2764 protected:
2765 ulonglong m_write_count = 0;
2766 // per row data
2767 ulonglong m_row_lock_count = 0;
2768 std::unordered_map<GL_INDEX_ID, ulonglong> m_auto_incr_map;
2769
2770 bool m_is_delayed_snapshot = false;
2771
2772 std::unordered_set<Rdb_tbl_def *> modified_tables;
2773
2774 private:
2775 /*
2776 Number of write operations this transaction had when we took the last
2777 savepoint (the idea is not to take another savepoint if we haven't made
2778 any changes)
2779 */
2780 ulonglong m_writes_at_last_savepoint;
2781
2782 protected:
2783 THD *m_thd = nullptr;
2784
2785 static std::multiset<Rdb_transaction *> s_tx_list;
2786 static Rds_mysql_mutex s_tx_list_mutex;
2787
2788 Rdb_io_perf *m_tbl_io_perf;
2789
2790 bool m_tx_read_only = false;
2791
2792 int m_timeout_sec; /* Cached value of @@rocksdb_lock_wait_timeout */
2793
2794 /* Maximum number of locks the transaction can have */
2795 ulonglong m_max_row_locks;
2796
2797 bool m_is_tx_failed = false;
2798 bool m_rollback_only = false;
2799
2800 std::shared_ptr<Rdb_snapshot_notifier> m_notifier;
2801
2802 // This should be used only when updating binlog information.
2803 virtual rocksdb::WriteBatchBase *get_write_batch() = 0;
2804 virtual bool commit_no_binlog() = 0;
2805 virtual rocksdb::Iterator *get_iterator(
2806 const rocksdb::ReadOptions &options,
2807 rocksdb::ColumnFamilyHandle *column_family) = 0;
2808
2809 /*
2810 @detail
2811 This function takes in the WriteBatch of the transaction to add
2812 all the AUTO_INCREMENT merges. It does so by iterating through
2813 m_auto_incr_map and then constructing key/value pairs to call merge upon.
2814
2815 @param wb
2816 */
2817 6865664 rocksdb::Status merge_auto_incr_map(rocksdb::WriteBatchBase *const wb) {
2818
3/4
✓ Branch 0 taken 6865754 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 6865730 times.
6865664 DBUG_EXECUTE_IF("myrocks_autoinc_upgrade", return rocksdb::Status::OK(););
2819
2820 // Iterate through the merge map merging all keys into data dictionary.
2821 6865730 rocksdb::Status s;
2822
2/2
✓ Branch 0 taken 132812 times.
✓ Branch 1 taken 6865846 times.
6998817 for (auto &it : m_auto_incr_map) {
2823 132846 s = dict_manager.get_dict_manager_selector_const(it.first.cf_id)
2824
2/4
✓ Branch 0 taken 132812 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 132838 times.
✗ Branch 3 not taken.
132846 ->put_auto_incr_val(wb, it.first, it.second);
2825
2/4
✓ Branch 0 taken 133000 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133000 times.
132995 if (!s.ok()) {
2826 return s;
2827 }
2828 }
2829 6865846 m_auto_incr_map.clear();
2830 6865717 return s;
2831 6865886 }
2832
2833 protected:
2834 /*
2835 The following two are helper functions to be overloaded by child classes.
2836 They should provide RocksDB's savepoint semantics.
2837 */
2838 virtual void do_set_savepoint() = 0;
2839 virtual rocksdb::Status do_pop_savepoint() = 0;
2840 virtual void do_rollback_to_savepoint() = 0;
2841
2842 public:
2843 rocksdb::ReadOptions m_read_opts;
2844 int64_t m_snapshot_timestamp = 0;
2845 bool m_ddl_transaction;
2846
2847 /*
2848 Tracks the number of tables in use through external_lock.
2849 This should not be reset during start_tx().
2850 */
2851 int64_t m_n_mysql_tables_in_use = 0;
2852
2853 /*
2854 for distinction between rdb_transaction_impl and rdb_writebatch_impl
2855 when using walk tx list
2856 */
2857 virtual bool is_writebatch_trx() const = 0;
2858
2859 932 static void init_mutex() {
2860 932 s_tx_list_mutex.init(key_mutex_tx_list, MY_MUTEX_INIT_FAST);
2861 932 }
2862
2863 899 static void term_mutex() {
2864
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 899 times.
899 assert(s_tx_list.size() == 0);
2865 899 s_tx_list_mutex.destroy();
2866 899 }
2867
2868 116 static void walk_tx_list(Rdb_tx_list_walker *walker) {
2869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 116 times.
116 assert(walker != nullptr);
2870
2871 116 RDB_MUTEX_LOCK_CHECK(s_tx_list_mutex);
2872
2873
3/4
✓ Branch 0 taken 339 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 339 times.
✓ Branch 3 taken 116 times.
455 for (auto it : s_tx_list) walker->process_tran(it);
2874
2875 116 RDB_MUTEX_UNLOCK_CHECK(s_tx_list_mutex);
2876 116 }
2877
2878 439 int set_status_error(THD *const thd, const rocksdb::Status &s,
2879 const Rdb_key_def &kd,
2880 const Rdb_tbl_def *const tbl_def) {
2881
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 439 times.
439 assert(!s.ok());
2882
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 439 times.
439 assert(tbl_def != nullptr);
2883
2884
2/2
✓ Branch 0 taken 296 times.
✓ Branch 1 taken 143 times.
439 if (s.IsTimedOut()) {
2885 /*
2886 SQL layer has weird expectations. If we return an error when
2887 doing a read in DELETE IGNORE, it will ignore the error ("because it's
2888 an IGNORE command!) but then will fail an assert, because "error code
2889 was returned, but no error happened". Do what InnoDB's
2890 convert_error_code_to_mysql() does: force a statement
2891 rollback before returning HA_ERR_LOCK_WAIT_TIMEOUT:
2892 */
2893 296 thd->mark_transaction_to_rollback(
2894 static_cast<bool>(rocksdb_rollback_on_timeout));
2895
2896 296 rocksdb_row_lock_wait_timeouts++;
2897
2898 296 return HA_ERR_LOCK_WAIT_TIMEOUT;
2899 }
2900
2901
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 104 times.
143 if (s.IsDeadlock()) {
2902 39 thd->mark_transaction_to_rollback(true /* whole transaction */);
2903 39 rocksdb_row_lock_deadlocks++;
2904 39 return HA_ERR_LOCK_DEADLOCK;
2905
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 19 times.
104 } else if (s.IsBusy()) {
2906 85 rocksdb_snapshot_conflict_errors++;
2907
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 82 times.
85 if (rocksdb_print_snapshot_conflict_queries) {
2908 char user_host_buff[MAX_USER_HOST_SIZE + 1];
2909
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 make_user_name(thd->security_context(), user_host_buff);
2910
11/22
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
3 LogPluginErrMsg(WARNING_LEVEL, 0,
2911 "Got snapshot conflict errors: User: %s Query: %.*s",
2912 user_host_buff, static_cast<int>(thd->query().length),
2913 thd->query().str);
2914 }
2915 85 return HA_ERR_ROCKSDB_STATUS_BUSY;
2916 }
2917
2918
3/6
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 19 times.
19 if (s.IsIOError() || s.IsCorruption()) {
2919 rdb_handle_io_error(s, RDB_IO_ERROR_GENERAL);
2920 }
2921
2922 19 return ha_rocksdb::rdb_error_to_mysql(s);
2923 }
2924
2925 13045834 THD *get_thd() const { return m_thd; }
2926
2927 /* Used for tracking io_perf counters */
2928 7992195 void io_perf_start(Rdb_io_perf *const io_perf) {
2929 /*
2930 Since perf_context is tracked per thread, it is difficult and expensive
2931 to maintain perf_context on a per table basis. Therefore, roll all
2932 perf_context data into the first table used in a query. This works well
2933 for single table queries and is probably good enough for queries that hit
2934 multiple tables.
2935
2936 perf_context stats gathering is started when the table lock is acquired
2937 or when ha_rocksdb::start_stmt is called in case of LOCK TABLES. They
2938 are recorded when the table lock is released, or when commit/rollback
2939 is called on the transaction, whichever comes first. Table lock release
2940 and commit/rollback can happen in different orders. In the case where
2941 the lock is released before commit/rollback is called, an extra step to
2942 gather stats during commit/rollback is needed.
2943 */
2944
4/4
✓ Branch 0 taken 7992189 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 141 times.
✓ Branch 3 taken 7992362 times.
15984692 if (m_tbl_io_perf == nullptr &&
2945
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 7992356 times.
7992189 io_perf->start(rocksdb_perf_context_level(m_thd))) {
2946 141 m_tbl_io_perf = io_perf;
2947 }
2948 7992503 }
2949
2950 4008373 void io_perf_end_and_record(void) {
2951
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 4008232 times.
4008373 if (m_tbl_io_perf != nullptr) {
2952 141 m_tbl_io_perf->end_and_record(rocksdb_perf_context_level(m_thd));
2953 141 m_tbl_io_perf = nullptr;
2954 }
2955 4008373 }
2956
2957 3983749 void io_perf_end_and_record(Rdb_io_perf *const io_perf) {
2958
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 3983707 times.
3983749 if (m_tbl_io_perf == io_perf) {
2959 42 io_perf_end_and_record();
2960 }
2961 3983749 }
2962
2963 112300888 void set_params(int timeout_sec_arg, int max_row_locks_arg) {
2964 112300888 m_timeout_sec = timeout_sec_arg;
2965 112300888 m_max_row_locks = max_row_locks_arg;
2966 112300888 set_lock_timeout(timeout_sec_arg);
2967 112299898 }
2968
2969 virtual void set_lock_timeout(int timeout_sec_arg) = 0;
2970
2971 49587101 ulonglong get_write_count() const { return m_write_count; }
2972
2973 12600560 ulonglong get_row_lock_count() const { return m_row_lock_count; }
2974
2975 12617910 void incr_row_lock_count() { ++m_row_lock_count; }
2976
2977 12622908 ulonglong get_max_row_lock_count() const { return m_max_row_locks; }
2978
2979 161 int get_timeout_sec() const { return m_timeout_sec; }
2980
2981 virtual void set_sync(bool sync) = 0;
2982
2983 virtual void release_lock(const Rdb_key_def &key_descr,
2984 const std::string &rowkey, bool force = false) = 0;
2985
2986 virtual bool prepare() = 0;
2987
2988 3554159 bool commit_or_rollback() {
2989 bool res;
2990
2/2
✓ Branch 0 taken 43915 times.
✓ Branch 1 taken 3510244 times.
3554159 if (m_is_tx_failed) {
2991 43915 rollback();
2992 43915 res = false;
2993 } else {
2994 3510244 res = commit();
2995 }
2996 3554073 return res;
2997 }
2998
2999 7093760 bool commit() {
3000
2/2
✓ Branch 0 taken 3661984 times.
✓ Branch 1 taken 3431855 times.
7093760 if (get_write_count() == 0) {
3001 3661984 rollback();
3002 3661828 return false;
3003
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3431852 times.
3431855 } else if (m_rollback_only) {
3004 /*
3005 Transactions marked as rollback_only are expected to be rolled back at
3006 prepare(). But there are some exceptions like below that prepare() is
3007 never called and commit() is called instead.
3008 1. Binlog is disabled
3009 2. No modification exists in binlog cache for the transaction (#195)
3010 In both cases, rolling back transaction is safe. Nothing is written to
3011 binlog.
3012 */
3013 3 my_error(ER_ROLLBACK_ONLY, MYF(0));
3014 3 rollback();
3015 3 return true;
3016 } else {
3017 3431852 return commit_no_binlog();
3018 }
3019 }
3020
3021 virtual void rollback() = 0;
3022
3023 3558276 void snapshot_created(const rocksdb::Snapshot *const snapshot) {
3024
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3558276 times.
3558276 assert(snapshot != nullptr);
3025
3026 3558276 m_read_opts.snapshot = snapshot;
3027 // TODO: Use snapshot timestamp from rocksdb Snapshot object itself. This
3028 // saves the extra call to fetch current time, and allows TTL compaction
3029 // (which uses rocksdb timestamp) to be consistent with TTL read filtering
3030 // (which uses this timestamp).
3031 //
3032 // There is no correctness problem though since m_snapshot_timestamp is
3033 // generally set after the snapshot has been created, so compaction is
3034 // not dropping anything that should have been visible.
3035 3558276 rdb->GetEnv()->GetCurrentTime(&m_snapshot_timestamp);
3036 3558382 m_is_delayed_snapshot = false;
3037 3558382 }
3038
3039 virtual void acquire_snapshot(bool acquire_now) = 0;
3040 virtual void release_snapshot() = 0;
3041
3042 269465 bool has_snapshot() const { return m_read_opts.snapshot != nullptr; }
3043
3044 private:
3045 // The Rdb_sst_info structures we are currently loading. In a partitioned
3046 // table this can have more than one entry
3047 std::vector<std::shared_ptr<Rdb_sst_info>> m_curr_bulk_load;
3048 std::string m_curr_bulk_load_tablename;
3049
3050 /* External merge sorts for bulk load: key ID -> merge sort instance */
3051 std::unordered_map<GL_INDEX_ID, Rdb_index_merge> m_key_merge;
3052
3053 /*
3054 Used to check for duplicate entries during fast unique secondary index
3055 creation.
3056 */
3057 struct unique_sk_buf_info {
3058 bool sk_buf_switch = false;
3059 rocksdb::Slice sk_memcmp_key;
3060 rocksdb::Slice sk_memcmp_key_old;
3061 uchar *dup_sk_buf = nullptr;
3062 uchar *dup_sk_buf_old = nullptr;
3063
3064 /*
3065 This method is meant to be called back to back during inplace creation
3066 of unique indexes. It will switch between two buffers, which
3067 will each store the memcmp form of secondary keys, which are then
3068 converted to slices in sk_memcmp_key or sk_memcmp_key_old.
3069
3070 Switching buffers on each iteration allows us to retain the
3071 sk_memcmp_key_old value for duplicate comparison.
3072 */
3073 66 inline uchar *swap_and_get_sk_buf() {
3074 66 sk_buf_switch = !sk_buf_switch;
3075
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 27 times.
66 return sk_buf_switch ? dup_sk_buf : dup_sk_buf_old;
3076 }
3077
3078 445 ~unique_sk_buf_info() {
3079 445 my_free(dup_sk_buf);
3080 445 dup_sk_buf = nullptr;
3081 445 my_free(dup_sk_buf_old);
3082 445 dup_sk_buf_old = nullptr;
3083 445 }
3084 };
3085
3086 public:
3087 24080865 int get_key_merge(GL_INDEX_ID kd_gl_id, rocksdb::ColumnFamilyHandle *cf,
3088 Rdb_index_merge **key_merge) {
3089 int res;
3090
1/2
✓ Branch 0 taken 24080865 times.
✗ Branch 1 not taken.
24080865 auto it = m_key_merge.find(kd_gl_id);
3091
2/2
✓ Branch 0 taken 475 times.
✓ Branch 1 taken 24080390 times.
24080865 if (it == m_key_merge.end()) {
3092
1/2
✓ Branch 0 taken 475 times.
✗ Branch 1 not taken.
475 m_key_merge.emplace(
3093
1/2
✓ Branch 0 taken 475 times.
✗ Branch 1 not taken.
475 std::piecewise_construct, std::make_tuple(kd_gl_id),
3094 std::make_tuple(
3095
3/6
✓ Branch 0 taken 475 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 475 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 475 times.
✗ Branch 5 not taken.
475 get_rocksdb_tmpdir(), THDVAR(get_thd(), merge_buf_size),
3096
1/2
✓ Branch 0 taken 475 times.
✗ Branch 1 not taken.
475 THDVAR(get_thd(), merge_combine_read_size),
3097
1/2
✓ Branch 0 taken 475 times.
✗ Branch 1 not taken.
475 THDVAR(get_thd(), merge_tmp_file_removal_delay_ms), cf));
3098
1/2
✓ Branch 0 taken 475 times.
✗ Branch 1 not taken.
475 it = m_key_merge.find(kd_gl_id);
3099
2/4
✓ Branch 0 taken 475 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 475 times.
475 if ((res = it->second.init()) != 0) {
3100 return res;
3101 }
3102 }
3103 24080865 *key_merge = &it->second;
3104 24080865 return HA_EXIT_SUCCESS;
3105 }
3106
3107 /* Finish bulk loading for all table handlers belongs to one connection */
3108 3243 int finish_bulk_load(bool *is_critical_error = nullptr,
3109 bool print_client_error = true,
3110 TABLE *table_arg = nullptr,
3111 char *table_name_arg = nullptr) {
3112
2/2
✓ Branch 0 taken 2716 times.
✓ Branch 1 taken 528 times.
3243 if (m_curr_bulk_load.size() == 0) {
3113
1/2
✓ Branch 0 taken 2716 times.
✗ Branch 1 not taken.
2716 if (is_critical_error) {
3114 2716 *is_critical_error = false;
3115 }
3116 2716 return HA_EXIT_SUCCESS;
3117 }
3118
3119
2/4
✓ Branch 0 taken 529 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 529 times.
528 if (THDVAR(m_thd, trace_sst_api)) {
3120 // NO_LINT_DEBUG
3121 LogPluginErrMsg(
3122 INFORMATION_LEVEL, 0,
3123 "SST Tracing : Finishing bulk loading operation for table '%s'",
3124 m_curr_bulk_load_tablename.c_str());
3125 }
3126
3127 529 Ensure_cleanup cleanup([&]() {
3128 // Always clear everything regardless of success/failure
3129 529 m_curr_bulk_load.clear();
3130 529 m_curr_bulk_load_tablename.clear();
3131 529 m_key_merge.clear();
3132
1/2
✓ Branch 0 taken 529 times.
✗ Branch 1 not taken.
529 });
3133
3134 529 int rc = 0;
3135
2/2
✓ Branch 0 taken 472 times.
✓ Branch 1 taken 57 times.
529 if (is_critical_error) {
3136 472 *is_critical_error = true;
3137 }
3138
3139 // PREPARE phase: finish all on-going bulk loading Rdb_sst_info and
3140 // collect all Rdb_sst_commit_info containing (SST files, cf)
3141
2/4
✓ Branch 0 taken 529 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 529 times.
529 if (THDVAR(m_thd, trace_sst_api)) {
3142 // NO_LINT_DEBUG
3143 LogPluginErrMsg(INFORMATION_LEVEL, 0,
3144 "SST Tracing : Finishing '%zu' active SST files",
3145 m_curr_bulk_load.size());
3146 }
3147
3148 529 int rc2 = 0;
3149 529 std::vector<Rdb_sst_info::Rdb_sst_commit_info> sst_commit_list;
3150
1/2
✓ Branch 0 taken 529 times.
✗ Branch 1 not taken.
529 sst_commit_list.reserve(m_curr_bulk_load.size());
3151
3152
2/2
✓ Branch 0 taken 586 times.
✓ Branch 1 taken 529 times.
1115 for (auto &sst_info : m_curr_bulk_load) {
3153 586 Rdb_sst_info::Rdb_sst_commit_info commit_info;
3154
3155 // Commit the list of SST files and move it to the end of
3156 // sst_commit_list, effectively transfer the ownership over
3157
1/2
✓ Branch 0 taken 586 times.
✗ Branch 1 not taken.
586 rc2 = sst_info->finish(&commit_info, print_client_error);
3158
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 586 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
586 if (rc2 && rc == 0) {
3159 // Don't return yet - make sure we finish all the SST infos
3160 rc = rc2;
3161 }
3162
3163 // Make sure we have work to do - we might be losing the race
3164
5/6
✓ Branch 0 taken 586 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 143 times.
✓ Branch 3 taken 443 times.
✓ Branch 4 taken 143 times.
✓ Branch 5 taken 443 times.
586 if (rc2 == 0 && commit_info.has_work()) {
3165
1/2
✓ Branch 0 taken 143 times.
✗ Branch 1 not taken.
143 sst_commit_list.emplace_back(std::move(commit_info));
3166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 143 times.
143 assert(!commit_info.has_work());
3167 }
3168 586 }
3169
3170
2/4
✓ Branch 0 taken 529 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 529 times.
529 if (THDVAR(m_thd, trace_sst_api)) {
3171 // NO_LINT_DEBUG
3172 LogPluginErrMsg(INFORMATION_LEVEL, 0,
3173 "SST Tracing : All active SST files finished");
3174 }
3175
3176
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 529 times.
529 if (rc) {
3177 return rc;
3178 }
3179
3180 // MERGING Phase: Flush the index_merge sort buffers into SST files in
3181 // Rdb_sst_info and collect all Rdb_sst_commit_info containing
3182 // (SST files, cf)
3183
2/2
✓ Branch 0 taken 433 times.
✓ Branch 1 taken 96 times.
529 if (!m_key_merge.empty()) {
3184
2/4
✓ Branch 0 taken 433 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 433 times.
433 if (THDVAR(m_thd, trace_sst_api)) {
3185 // NO_LINT_DEBUG
3186 LogPluginErrMsg(
3187 INFORMATION_LEVEL, 0,
3188 "SST Tracing : Started flushing index_merge sort buffer");
3189 }
3190
3191 433 Ensure_cleanup malloc_cleanup([]() {
3192 /*
3193 Explicitly tell jemalloc to clean up any unused dirty pages at this
3194 point.
3195 See https://reviews.facebook.net/D63723 for more details.
3196 */
3197 433 purge_all_jemalloc_arenas();
3198
1/2
✓ Branch 0 taken 433 times.
✗ Branch 1 not taken.
433 });
3199
3200 433 rocksdb::Slice merge_key;
3201 433 rocksdb::Slice merge_val;
3202
2/2
✓ Branch 0 taken 475 times.
✓ Branch 1 taken 412 times.
887 for (auto it = m_key_merge.begin(); it != m_key_merge.end(); it++) {
3203 475 GL_INDEX_ID index_id = it->first;
3204 std::shared_ptr<const Rdb_key_def> keydef =
3205
1/2
✓ Branch 0 taken 475 times.
✗ Branch 1 not taken.
475 ddl_manager.safe_find(index_id);
3206 475 std::string table_name;
3207
2/2
✓ Branch 0 taken 358 times.
✓ Branch 1 taken 117 times.
475 if (table_name_arg) {
3208
1/2
✓ Branch 0 taken 358 times.
✗ Branch 1 not taken.
358 table_name = table_name_arg;
3209 } else {
3210
2/4
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
117 table_name = ddl_manager.safe_get_table_name(index_id);
3211 // Rdb_sst_info expects a denormalized table name in the form of
3212 // "./database/table"
3213 117 std::replace(table_name.begin(), table_name.end(), '.', '/');
3214
1/2
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
117 table_name = "./" + table_name;
3215 }
3216
3217 // Unable to find key definition or table name since the
3218 // table could have been dropped.
3219 // TODO(herman): there is a race here between dropping the table
3220 // and detecting a drop here. If the table is dropped while bulk
3221 // loading is finishing, these keys being added here may
3222 // be missed by the compaction filter and not be marked for
3223 // removal. It is unclear how to lock the sql table from the storage
3224 // engine to prevent modifications to it while bulk load is occurring.
3225
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 469 times.
475 if (keydef == nullptr) {
3226
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (is_critical_error) {
3227 // We used to set the error but simply ignores it. This follows
3228 // current behavior and we should revisit this later
3229 6 *is_critical_error = false;
3230 }
3231 6 return HA_ERR_KEY_NOT_FOUND;
3232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 469 times.
469 } else if (table_name.empty()) {
3233 if (is_critical_error) {
3234 // We used to set the error but simply ignores it. This follows
3235 // current behavior and we should revisit this later
3236 *is_critical_error = false;
3237 }
3238 return HA_ERR_NO_SUCH_TABLE;
3239 }
3240
3241 // Currently, unique indexes only checked in the inplace alter path,
3242 // but not in allow_sk bulk load path.
3243 bool is_unique_index =
3244
2/2
✓ Branch 0 taken 355 times.
✓ Branch 1 taken 114 times.
824 table_arg &&
3245
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 328 times.
355 table_arg->key_info[keydef->get_keyno()].flags & HA_NOSAME;
3246
3247 469 const std::string &index_name = keydef->get_name();
3248
3249
2/4
✓ Branch 0 taken 469 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 469 times.
469 if (THDVAR(m_thd, trace_sst_api)) {
3250 std::string full_name;
3251 int err = rdb_normalize_tablename(table_name, &full_name);
3252 if (err != HA_EXIT_SUCCESS) {
3253 full_name = table_name;
3254 }
3255
3256 // NO_LINT_DEBUG
3257 LogPluginErrMsg(
3258 INFORMATION_LEVEL, 0,
3259 "SST Tracing : Flushing index_merge sort buffer for table '%s' "
3260 "and index '%s'",
3261 full_name.c_str(), index_name.c_str());
3262 }
3263
3264 469 Rdb_index_merge &rdb_merge = it->second;
3265
3266 auto sst_info = std::make_shared<Rdb_sst_info>(
3267 469 rdb, table_name, index_name, rdb_merge.get_cf(),
3268
2/4
✓ Branch 0 taken 469 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 469 times.
✗ Branch 3 not taken.
938 *rocksdb_db_options, THDVAR(get_thd(), trace_sst_api));
3269
3270
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 445 times.
469 if (keydef->is_partial_index()) {
3271
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
24 if (!THDVAR(m_thd, bulk_load_partial_index)) continue;
3272 // For partial indexes, we only want to materialize groups that reach
3273 // the materialization threshold. The idea is to buffer the rows up to
3274 // the threshold, and only actually insert the keys once we break the
3275 // threshold.
3276 24 bool materialized = false;
3277 24 rocksdb::Slice cur_prefix;
3278 24 std::vector<std::pair<rocksdb::Slice, rocksdb::Slice>> keys;
3279
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 MEM_ROOT mem_root;
3280
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 init_sql_alloc(PSI_NOT_INSTRUMENTED, &mem_root, 4024);
3281
3282
3/4
✓ Branch 0 taken 1344 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1320 times.
✓ Branch 3 taken 24 times.
1344 while ((rc2 = rdb_merge.next(&merge_key, &merge_val)) == 0) {
3283
4/4
✓ Branch 0 taken 1296 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 240 times.
✓ Branch 3 taken 1080 times.
2616 if (cur_prefix.size() == 0 ||
3284
3/4
✓ Branch 0 taken 1296 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 216 times.
✓ Branch 3 taken 1080 times.
1296 !keydef->value_matches_prefix(merge_key, cur_prefix)) {
3285
6/6
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 30 times.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 210 times.
240 if (keydef->m_is_reverse_cf && materialized) {
3286 // Write sentinel before moving to next prefix.
3287
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 rc2 = sst_info->put(cur_prefix, rocksdb::Slice());
3288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (rc2 != 0) {
3289 break;
3290 }
3291 }
3292
3293 // This is a new group, so clear any rows buffered from a prior
3294 // group.
3295
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 mem_root.ClearForReuse();
3296 240 keys.clear();
3297 240 materialized = false;
3298
3299 // Determine the length of the new group prefix
3300 240 Rdb_string_reader reader(&merge_key);
3301
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
240 if ((!reader.read(Rdb_key_def::INDEX_NUMBER_SIZE))) {
3302 rc2 = HA_ERR_ROCKSDB_CORRUPT_DATA;
3303 break;
3304 }
3305
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 240 times.
480 for (uint i = 0; i < keydef->partial_index_keyparts(); i++) {
3306
2/4
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 240 times.
240 if (keydef->read_memcmp_key_part(&reader, i) > 0) {
3307 rc2 = HA_ERR_ROCKSDB_CORRUPT_DATA;
3308 break;
3309 }
3310 }
3311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
240 if (rc2) break;
3312
3313 size_t cur_prefix_len =
3314 240 reader.get_current_ptr() - merge_key.data();
3315
3316
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 const char *key = (const char *)memdup_root(
3317 240 &mem_root, merge_key.data(), cur_prefix_len);
3318
3319 // Set the current prefix.
3320 240 cur_prefix = rocksdb::Slice(key, cur_prefix_len);
3321 }
3322
3323
2/2
✓ Branch 0 taken 1080 times.
✓ Branch 1 taken 240 times.
1320 if (!materialized) {
3324 // Bulk load the keys if threshold is exceeded.
3325
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 960 times.
1080 if (keys.size() >= keydef->partial_index_threshold()) {
3326
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 30 times.
120 if (!keydef->m_is_reverse_cf) {
3327 // Write sentinel
3328
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 rc2 = sst_info->put(cur_prefix, rocksdb::Slice());
3329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if (rc2 != 0) {
3330 break;
3331 }
3332 }
3333
3334
2/2
✓ Branch 0 taken 600 times.
✓ Branch 1 taken 120 times.
720 for (const auto &k : keys) {
3335
2/4
✓ Branch 0 taken 600 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 600 times.
600 if ((rc2 = sst_info->put(k.first, k.second) != 0)) {
3336 break;
3337 }
3338 }
3339
3340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (rc2 != 0) {
3341 break;
3342 }
3343
3344 120 materialized = true;
3345 120 keys.clear();
3346 } else {
3347 // Threshold not exceeded, just buffer the row in the keys
3348 // vector.
3349
1/2
✓ Branch 0 taken 960 times.
✗ Branch 1 not taken.
1920 const char *key = (const char *)memdup_root(
3350 960 &mem_root, merge_key.data(), merge_key.size());
3351
1/2
✓ Branch 0 taken 960 times.
✗ Branch 1 not taken.
1920 const char *val = (const char *)memdup_root(
3352 960 &mem_root, merge_val.data(), merge_val.size());
3353
1/2
✓ Branch 0 taken 960 times.
✗ Branch 1 not taken.
960 keys.emplace_back(rocksdb::Slice(key, merge_key.size()),
3354 1920 rocksdb::Slice(val, merge_val.size()));
3355 }
3356 }
3357
3358
2/2
✓ Branch 0 taken 360 times.
✓ Branch 1 taken 960 times.
1320 if (materialized) {
3359
1/2
✓ Branch 0 taken 360 times.
✗ Branch 1 not taken.
360 rc2 = sst_info->put(merge_key, merge_val);
3360
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 360 times.
360 if (rc != 0) {
3361 rc = rc2;
3362 break;
3363 }
3364 }
3365
3366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1320 times.
1320 if (rc2) break;
3367 }
3368
3369
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 24 times.
24 if (!rc2 && keydef->m_is_reverse_cf && materialized) {
3370 // Write sentinel before moving to next prefix.
3371 rc2 = sst_info->put(cur_prefix, rocksdb::Slice());
3372 if (rc2 != 0) {
3373 break;
3374 }
3375 }
3376
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
24 } else {
3377 445 struct unique_sk_buf_info sk_info;
3378
3379
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 418 times.
445 if (is_unique_index) {
3380 27 uint max_packed_sk_len = keydef->max_storage_fmt_length();
3381 27 sk_info.dup_sk_buf = reinterpret_cast<uchar *>(
3382
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 my_malloc(PSI_NOT_INSTRUMENTED, max_packed_sk_len, MYF(0)));
3383 27 sk_info.dup_sk_buf_old = reinterpret_cast<uchar *>(
3384
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 my_malloc(PSI_NOT_INSTRUMENTED, max_packed_sk_len, MYF(0)));
3385 }
3386
3387
3/4
✓ Branch 0 taken 24079945 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24079515 times.
✓ Branch 3 taken 430 times.
24079945 while ((rc2 = rdb_merge.next(&merge_key, &merge_val)) == 0) {
3388 /* Perform uniqueness check if needed */
3389
4/4
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 24079449 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 24079500 times.
24079581 if (is_unique_index &&
3390
3/4
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 51 times.
66 check_duplicate_sk(table_arg, *keydef, &merge_key, &sk_info)) {
3391 /*
3392 Duplicate entry found when trying to create unique secondary
3393 key. We need to unpack the record into new_table_arg->record[0]
3394 as it is used inside print_keydup_error so that the error
3395 message shows the duplicate record.
3396 */
3397
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
15 if (keydef->unpack_record(table_arg, table_arg->record[0],
3398 &merge_key, &merge_val, false)) {
3399 /* Should never reach here */
3400 assert(0);
3401 }
3402
3403 15 rc = ER_DUP_ENTRY;
3404
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (is_critical_error) {
3405 15 *is_critical_error = false;
3406 }
3407 15 break;
3408 }
3409
3410 /*
3411 Insert key and slice to SST via SSTFileWriter API.
3412 */
3413
2/4
✓ Branch 0 taken 24079500 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24079500 times.
24079500 if ((rc2 = sst_info->put(merge_key, merge_val)) != 0) {
3414 rc = rc2;
3415
3416 // Don't return yet - make sure we finish the sst_info
3417 break;
3418 }
3419 }
3420 445 }
3421
3422 // -1 => no more items
3423
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 469 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
469 if (rc2 > 0 && rc == 0) {
3424 rc = rc2;
3425 }
3426
3427 469 Rdb_sst_info::Rdb_sst_commit_info commit_info;
3428
1/2
✓ Branch 0 taken 469 times.
✗ Branch 1 not taken.
469 rc2 = sst_info->finish(&commit_info, print_client_error);
3429
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 469 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
469 if (rc2 != 0 && rc == 0) {
3430 // Only set the error from sst_info->finish if finish failed and we
3431 // didn't fail before. In other words, we don't have finish's
3432 // success mask earlier failures
3433 rc = rc2;
3434 }
3435
3436
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 454 times.
469 if (rc) {
3437 15 return rc;
3438 }
3439
3440
1/2
✓ Branch 0 taken 454 times.
✗ Branch 1 not taken.
454 if (commit_info.has_work()) {
3441
1/2
✓ Branch 0 taken 454 times.
✗ Branch 1 not taken.
454 sst_commit_list.emplace_back(std::move(commit_info));
3442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 454 times.
454 assert(!commit_info.has_work());
3443 }
3444
8/14
✓ Branch 0 taken 454 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 454 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✓ Branch 6 taken 454 times.
✓ Branch 7 taken 21 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 454 times.
✓ Branch 11 taken 21 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
526 }
3445
3446
2/4
✓ Branch 0 taken 412 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 412 times.
412 if (THDVAR(m_thd, trace_sst_api)) {
3447 // NO_LINT_DEBUG
3448 LogPluginErrMsg(
3449 INFORMATION_LEVEL, 0,
3450 "SST Tracing : Flushing index_merge sort buffer completed");
3451 }
3452
2/2
✓ Branch 0 taken 412 times.
✓ Branch 1 taken 21 times.
433 }
3453
3454 // Early return in case we lost the race completely and end up with no
3455 // work at all
3456
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 501 times.
508 if (sst_commit_list.size() == 0) {
3457 7 return rc;
3458 }
3459
3460 // INGEST phase: Group all Rdb_sst_commit_info by cf (as they might
3461 // have the same cf across different indexes) and call out to RocksDB
3462 // to ingest all SST files in one atomic operation
3463 501 rocksdb::IngestExternalFileOptions options;
3464 501 options.move_files = true;
3465 501 options.snapshot_consistency = false;
3466 501 options.allow_global_seqno = false;
3467 501 options.allow_blocking_flush = false;
3468
3469 std::map<rocksdb::ColumnFamilyHandle *, rocksdb::IngestExternalFileArg>
3470 501 arg_map;
3471
3472 // Group by column_family
3473
2/2
✓ Branch 0 taken 594 times.
✓ Branch 1 taken 501 times.
1095 for (auto &commit_info : sst_commit_list) {
3474
3/4
✓ Branch 0 taken 594 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 522 times.
✓ Branch 3 taken 72 times.
594 if (arg_map.find(commit_info.get_cf()) == arg_map.end()) {
3475 522 rocksdb::IngestExternalFileArg arg;
3476 522 arg.column_family = commit_info.get_cf(),
3477
1/2
✓ Branch 0 taken 522 times.
✗ Branch 1 not taken.
522 arg.external_files = commit_info.get_committed_files(),
3478 522 arg.options = options;
3479
3480
1/2
✓ Branch 0 taken 522 times.
✗ Branch 1 not taken.
522 arg_map.emplace(commit_info.get_cf(), arg);
3481 522 } else {
3482
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 auto &files = arg_map[commit_info.get_cf()].external_files;
3483
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 files.insert(files.end(), commit_info.get_committed_files().begin(),
3484 72 commit_info.get_committed_files().end());
3485 }
3486 }
3487
3488 501 std::vector<rocksdb::IngestExternalFileArg> args;
3489 501 size_t file_count = 0;
3490
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 501 times.
1023 for (auto &cf_files_pair : arg_map) {
3491
1/2
✓ Branch 0 taken 522 times.
✗ Branch 1 not taken.
522 args.push_back(cf_files_pair.second);
3492 522 file_count += cf_files_pair.second.external_files.size();
3493 }
3494
3495
2/4
✓ Branch 0 taken 501 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 501 times.
501 if (THDVAR(m_thd, trace_sst_api)) {
3496 // NO_LINT_DEBUG
3497 LogPluginErrMsg(
3498 INFORMATION_LEVEL, 0,
3499 "SST Tracing: Calling IngestExternalFile with '%zu' files",
3500 file_count);
3501 }
3502
1/2
✓ Branch 0 taken 501 times.
✗ Branch 1 not taken.
501 const rocksdb::Status s = rdb->IngestExternalFiles(args);
3503
2/4
✓ Branch 0 taken 501 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 501 times.
501 if (THDVAR(m_thd, trace_sst_api)) {
3504 LogPluginErrMsg(INFORMATION_LEVEL, 0,
3505 "SST Tracing: IngestExternalFile '%zu' files returned %s",
3506 file_count, s.ok() ? "ok" : "not ok");
3507 }
3508
3509
3/4
✓ Branch 0 taken 501 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 492 times.
501 if (!s.ok()) {
3510
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 if (print_client_error) {
3511
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 Rdb_sst_info::report_error_msg(s, nullptr);
3512 }
3513 9 return HA_ERR_ROCKSDB_BULK_LOAD;
3514 }
3515
3516 // COMMIT phase: mark everything as completed. This avoids SST file
3517 // deletion kicking in. Otherwise SST files would get deleted if this
3518 // entire operation is aborted
3519
2/2
✓ Branch 0 taken 585 times.
✓ Branch 1 taken 492 times.
1077 for (auto &commit_info : sst_commit_list) {
3520 585 commit_info.commit();
3521 }
3522
3523
2/4
✓ Branch 0 taken 492 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 492 times.
492 if (THDVAR(m_thd, trace_sst_api)) {
3524 // NO_LINT_DEBUG
3525 LogPluginErrMsg(
3526 INFORMATION_LEVEL, 0,
3527 "SST Tracing : Bulk loading operation completed for table '%s'",
3528 m_curr_bulk_load_tablename.c_str());
3529 }
3530
3531 492 return rc;
3532 529 }
3533
3534 /**
3535 Check whether secondary key value is duplicate or not
3536
3537 @param[in] table_arg the table currently working on
3538 @param[in key_def the key_def is being checked
3539 @param[in] key secondary key storage data
3540 @param[out] sk_info hold secondary key memcmp datas(new/old)
3541 @return
3542 HA_EXIT_SUCCESS OK
3543 other HA_ERR error code (can be SE-specific)
3544 */
3545
3546 66 int check_duplicate_sk(const TABLE *table_arg, const Rdb_key_def &key_def,
3547 const rocksdb::Slice *key,
3548 struct unique_sk_buf_info *sk_info) {
3549 66 uint n_null_fields = 0;
3550
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 const rocksdb::Comparator *index_comp = key_def.get_cf()->GetComparator();
3551
3552 /* Get proper SK buffer. */
3553 66 uchar *sk_buf = sk_info->swap_and_get_sk_buf();
3554
3555 /* Get memcmp form of sk without extended pk tail */
3556 uint sk_memcmp_size =
3557
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 key_def.get_memcmp_sk_parts(table_arg, *key, sk_buf, &n_null_fields);
3558
3559 66 sk_info->sk_memcmp_key =
3560 66 rocksdb::Slice(reinterpret_cast<char *>(sk_buf), sk_memcmp_size);
3561
3562
6/6
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 51 times.
96 if (sk_info->sk_memcmp_key_old.size() > 0 && n_null_fields == 0 &&
3563
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 index_comp->Compare(sk_info->sk_memcmp_key,
3564
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 sk_info->sk_memcmp_key_old) == 0) {
3565 15 return 1;
3566 }
3567
3568 51 sk_info->sk_memcmp_key_old = sk_info->sk_memcmp_key;
3569 51 return 0;
3570 }
3571
3572 589 int start_bulk_load(ha_rocksdb *const bulk_load,
3573 std::shared_ptr<Rdb_sst_info> sst_info) {
3574 /*
3575 If we already have an open bulk load of a table and the name doesn't
3576 match the current one, close out the currently running one. This allows
3577 multiple bulk loads to occur on a partitioned table, but then closes
3578 them all out when we switch to another table.
3579 */
3580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 589 times.
589 assert(bulk_load != nullptr);
3581
3582
6/6
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 475 times.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 57 times.
✓ Branch 4 taken 57 times.
✓ Branch 5 taken 532 times.
703 if (!m_curr_bulk_load.empty() &&
3583 114 bulk_load->get_table_basename() != m_curr_bulk_load_tablename) {
3584 57 const auto res = finish_bulk_load();
3585
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 54 times.
57 if (res != HA_EXIT_SUCCESS) {
3586 3 return res;
3587 }
3588 }
3589
3590
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 583 times.
586 if (THDVAR(m_thd, trace_sst_api)) {
3591 // NO_LINT_DEBUG
3592
9/18
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LogPluginErrMsg(
3593 INFORMATION_LEVEL, 0,
3594 "SST Tracing : Starting bulk loading operation for table '%s'",
3595 bulk_load->get_table_basename().c_str());
3596 }
3597
3598 /*
3599 This used to track ha_rocksdb handler objects, but those can be
3600 freed by the table cache while this was referencing them. Instead
3601 of tracking ha_rocksdb handler objects, this now tracks the
3602 Rdb_sst_info allocated, and both the ha_rocksdb handler and the
3603 Rdb_transaction both have shared pointers to them.
3604
3605 On transaction complete, it will commit each Rdb_sst_info structure found.
3606 If the ha_rocksdb object is freed, etc., it will also commit
3607 the Rdb_sst_info. The Rdb_sst_info commit path needs to be idempotent.
3608 */
3609 586 m_curr_bulk_load.push_back(sst_info);
3610 586 m_curr_bulk_load_tablename = bulk_load->get_table_basename();
3611 586 return HA_EXIT_SUCCESS;
3612 }
3613
3614 167 int num_ongoing_bulk_load() const { return m_curr_bulk_load.size(); }
3615
3616 475 const char *get_rocksdb_tmpdir() const {
3617 475 const char *tmp_dir = THDVAR(get_thd(), tmpdir);
3618
3619 /*
3620 We want to treat an empty string as nullptr, in these cases DDL operations
3621 will use the default --tmpdir passed to mysql instead.
3622 */
3623
2/4
✓ Branch 0 taken 475 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 475 times.
✗ Branch 3 not taken.
475 if (tmp_dir != nullptr && *tmp_dir == '\0') {
3624 475 tmp_dir = nullptr;
3625 }
3626 475 return (tmp_dir);
3627 }
3628
3629 /*
3630 Flush the data accumulated so far. This assumes we're doing a bulk insert.
3631
3632 @detail
3633 This should work like transaction commit, except that we don't
3634 synchronize with the binlog (there is no API that would allow to have
3635 binlog flush the changes accumulated so far and return its current
3636 position)
3637
3638 @todo
3639 Add test coverage for what happens when somebody attempts to do bulk
3640 inserts while inside a multi-statement transaction.
3641 */
3642 478 bool flush_batch() {
3643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 478 times.
478 if (get_write_count() == 0) return false;
3644
3645 /* Commit the current transaction */
3646
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 478 times.
478 if (commit_no_binlog()) return true;
3647
3648
1/2
✓ Branch 0 taken 478 times.
✗ Branch 1 not taken.
478 DEBUG_SYNC(m_thd, "rocksdb.flush_batch");
3649
3650 /* Start another one */
3651 478 start_tx();
3652 478 return false;
3653 }
3654
3655 8164663 void set_auto_incr(const GL_INDEX_ID &gl_index_id, ulonglong curr_id) {
3656 16412021 m_auto_incr_map[gl_index_id] =
3657 8164663 std::max(m_auto_incr_map[gl_index_id], curr_id);
3658 8254188 }
3659
3660 #ifndef NDEBUG
3661 410 ulonglong get_auto_incr(const GL_INDEX_ID &gl_index_id) {
3662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 410 times.
410 if (m_auto_incr_map.count(gl_index_id) > 0) {
3663 return m_auto_incr_map[gl_index_id];
3664 }
3665 410 return 0;
3666 }
3667 #endif
3668
3669 virtual rocksdb::Status put(rocksdb::ColumnFamilyHandle *const column_family,
3670 const rocksdb::Slice &key,
3671 const rocksdb::Slice &value,
3672 const bool assume_tracked) = 0;
3673 virtual rocksdb::Status delete_key(
3674 rocksdb::ColumnFamilyHandle *const column_family,
3675 const rocksdb::Slice &key, const bool assume_tracked) = 0;
3676 virtual rocksdb::Status single_delete(
3677 rocksdb::ColumnFamilyHandle *const column_family,
3678 const rocksdb::Slice &key, const bool assume_tracked) = 0;
3679
3680 virtual bool has_modifications() const = 0;
3681
3682 virtual rocksdb::WriteBatchBase *get_indexed_write_batch() = 0;
3683 /*
3684 Return a WriteBatch that one can write to. The writes will skip any
3685 transaction locking. The writes will NOT be visible to the transaction.
3686 */
3687 rocksdb::WriteBatchBase *get_blind_write_batch() {
3688 return get_indexed_write_batch()->GetWriteBatch();
3689 }
3690
3691 virtual rocksdb::Status get(rocksdb::ColumnFamilyHandle *const column_family,
3692 const rocksdb::Slice &key,
3693 rocksdb::PinnableSlice *const value) const = 0;
3694 virtual rocksdb::Status get_for_update(const Rdb_key_def &key_descr,
3695 const rocksdb::Slice &key,
3696 rocksdb::PinnableSlice *const value,
3697 bool exclusive, const bool do_validate,
3698 bool no_wait) = 0;
3699
3700 262898 rocksdb::Iterator *get_iterator(
3701 rocksdb::ColumnFamilyHandle *const column_family, bool skip_bloom_filter,
3702 const rocksdb::Slice &eq_cond_lower_bound,
3703 const rocksdb::Slice &eq_cond_upper_bound, bool read_current = false,
3704 bool create_snapshot = true) {
3705 // Make sure we are not doing both read_current (which implies we don't
3706 // want a snapshot) and create_snapshot which makes sure we create
3707 // a snapshot
3708
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 262898 times.
262898 assert(column_family != nullptr);
3709
3/4
✓ Branch 0 taken 10525 times.
✓ Branch 1 taken 252373 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10525 times.
262898 assert(!read_current || !create_snapshot);
3710
3711
3/4
✓ Branch 0 taken 252373 times.
✓ Branch 1 taken 10525 times.
✓ Branch 2 taken 252373 times.
✗ Branch 3 not taken.
262898 if (create_snapshot) acquire_snapshot(true);
3712
3713
1/2
✓ Branch 0 taken 262898 times.
✗ Branch 1 not taken.
262898 rocksdb::ReadOptions options = m_read_opts;
3714
1/2
✓ Branch 0 taken 262898 times.
✗ Branch 1 not taken.
262898 const bool fill_cache = !THDVAR(get_thd(), skip_fill_cache);
3715
3716
2/2
✓ Branch 0 taken 200306 times.
✓ Branch 1 taken 62592 times.
262898 if (skip_bloom_filter) {
3717 const bool enable_iterate_bounds =
3718
1/2
✓ Branch 0 taken 200306 times.
✗ Branch 1 not taken.
200306 THDVAR(get_thd(), enable_iterate_bounds);
3719 200306 options.total_order_seek = true;
3720 200306 options.iterate_lower_bound =
3721
2/2
✓ Branch 0 taken 200297 times.
✓ Branch 1 taken 9 times.
200306 enable_iterate_bounds ? &eq_cond_lower_bound : nullptr;
3722 200306 options.iterate_upper_bound =
3723
2/2
✓ Branch 0 taken 200297 times.
✓ Branch 1 taken 9 times.
200306 enable_iterate_bounds ? &eq_cond_upper_bound : nullptr;
3724 } else {
3725 // With this option, Iterator::Valid() returns false if key
3726 // is outside of the prefix bloom filter range set at Seek().
3727 // Must not be set to true if not using bloom filter.
3728 62592 options.prefix_same_as_start = true;
3729 }
3730 262898 options.fill_cache = fill_cache;
3731
2/2
✓ Branch 0 taken 10525 times.
✓ Branch 1 taken 252373 times.
262898 if (read_current) {
3732 10525 options.snapshot = nullptr;
3733 }
3734
1/2
✓ Branch 0 taken 262898 times.
✗ Branch 1 not taken.
525796 return get_iterator(options, column_family);
3735 262898 }
3736
3737 virtual bool is_tx_started() const = 0;
3738 virtual void start_tx() = 0;
3739 virtual void start_stmt() = 0;
3740 virtual void set_name() = 0;
3741
3742 protected:
3743 // Non-virtual functions with actions to be done on transaction start and
3744 // commit.
3745 3432330 void on_commit() {
3746 time_t tm;
3747 3432330 tm = time(nullptr);
3748
2/2
✓ Branch 0 taken 3433069 times.
✓ Branch 1 taken 3432330 times.
6865399 for (auto &it : modified_tables) {
3749 3433069 it->m_update_time = tm;
3750 }
3751 3432330 modified_tables.clear();
3752 3432330 }
3753 7141186 void on_rollback() { modified_tables.clear(); }
3754
3755 public:
3756 70948633 void log_table_write_op(Rdb_tbl_def *tbl) { modified_tables.insert(tbl); }
3757
3758 3580605 void set_initial_savepoint() {
3759 /*
3760 Set the initial savepoint. If the first statement in the transaction
3761 fails, we need something to roll back to, without rolling back the
3762 entire transaction.
3763 */
3764 3580605 do_set_savepoint();
3765 3580897 m_writes_at_last_savepoint = m_write_count;
3766 3580897 }
3767
3768 /*
3769 Called when a "top-level" statement inside a transaction completes
3770 successfully and its changes become part of the transaction's changes.
3771 */
3772 836497 int make_stmt_savepoint_permanent() {
3773 // Take another RocksDB savepoint only if we had changes since the last
3774 // one. This is very important for long transactions doing lots of
3775 // SELECTs.
3776
2/2
✓ Branch 0 taken 49456 times.
✓ Branch 1 taken 787041 times.
836497 if (m_writes_at_last_savepoint != m_write_count) {
3777
1/2
✓ Branch 0 taken 49456 times.
✗ Branch 1 not taken.
49456 rocksdb::Status status = rocksdb::Status::NotFound();
3778
4/6
✓ Branch 0 taken 98912 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 98912 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 49456 times.
✓ Branch 5 taken 49456 times.
98912 while ((status = do_pop_savepoint()) == rocksdb::Status::OK()) {
3779 }
3780
3781
3/6
✓ Branch 0 taken 49456 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49456 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 49456 times.
49456 if (status != rocksdb::Status::NotFound()) {
3782 return HA_EXIT_FAILURE;
3783 }
3784
3785
1/2
✓ Branch 0 taken 49456 times.
✗ Branch 1 not taken.
49456 do_set_savepoint();
3786 49456 m_writes_at_last_savepoint = m_write_count;
3787
1/2
✓ Branch 0 taken 49456 times.
✗ Branch 1 not taken.
49456 }
3788
3789 836497 return HA_EXIT_SUCCESS;
3790 }
3791
3792 /*
3793 Rollback to the savepoint we've set before the last statement
3794 */
3795 3386 void rollback_to_stmt_savepoint() {
3796
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 3248 times.
3386 if (m_writes_at_last_savepoint != m_write_count) {
3797 138 do_rollback_to_savepoint();
3798 /*
3799 RollbackToSavePoint "removes the most recent SetSavePoint()", so
3800 we need to set it again so that next statement can roll back to this
3801 stage.
3802 It's ok to do it here at statement end (instead of doing it at next
3803 statement start) because setting a savepoint is cheap.
3804 */
3805 138 do_set_savepoint();
3806 138 m_write_count = m_writes_at_last_savepoint;
3807 }
3808 3386 }
3809
3810 virtual void rollback_stmt() = 0;
3811
3812 424162 void set_tx_failed(bool failed_arg) { m_is_tx_failed = failed_arg; }
3813
3814 3854694 bool can_prepare() const {
3815
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 3854667 times.
3854694 if (m_rollback_only) {
3816 27 my_error(ER_ROLLBACK_ONLY, MYF(0));
3817 27 return false;
3818 }
3819 3854667 return true;
3820 }
3821
3822 45 int rollback_to_savepoint(void *const savepoint) {
3823
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 18 times.
45 if (has_modifications()) {
3824 27 my_error(ER_ROLLBACK_TO_SAVEPOINT, MYF(0));
3825 27 m_rollback_only = true;
3826 27 return HA_EXIT_FAILURE;
3827 }
3828 18 return HA_EXIT_SUCCESS;
3829 }
3830
3831 /*
3832 This is used by transactions started with "START TRANSACTION WITH "
3833 "CONSISTENT [ROCKSDB] SNAPSHOT". When tx_read_only is turned on,
3834 snapshot has to be created via DB::GetSnapshot(), not via Transaction
3835 API.
3836 */
3837 11621300 bool is_tx_read_only() const { return m_tx_read_only; }
3838
3839 3587499 void set_tx_read_only(bool val) { m_tx_read_only = val; }
3840
3841 /*
3842 Add or remove from the global list of active transactions
3843 needed by information_schema queries.
3844 */
3845 2576 void add_to_global_trx_list() {
3846 2576 RDB_MUTEX_LOCK_CHECK(s_tx_list_mutex);
3847
1/2
✓ Branch 0 taken 2579 times.
✗ Branch 1 not taken.
2579 s_tx_list.insert(this);
3848 2579 RDB_MUTEX_UNLOCK_CHECK(s_tx_list_mutex);
3849 2579 }
3850
3851 2534 void remove_from_global_trx_list(void) {
3852
9/16
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2533 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
2534 DBUG_EXECUTE_IF("rocksdb_trx_list_crash", {
3853 THD *thd = new THD();
3854 thd->thread_stack = reinterpret_cast<char *>(&(thd));
3855 thd->store_globals();
3856
3857 const char act[] =
3858 "now signal destructor_started wait_for trx_list_query";
3859 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
3860
3861 thd->restore_globals();
3862 delete thd;
3863 });
3864 2536 RDB_MUTEX_LOCK_CHECK(s_tx_list_mutex);
3865
1/2
✓ Branch 0 taken 2537 times.
✗ Branch 1 not taken.
2537 s_tx_list.erase(this);
3866 2537 RDB_MUTEX_UNLOCK_CHECK(s_tx_list_mutex);
3867 2537 }
3868
3869 2579 explicit Rdb_transaction(THD *const thd)
3870
1/2
✓ Branch 0 taken 2576 times.
✗ Branch 1 not taken.
2579 : m_thd(thd), m_tbl_io_perf(nullptr) {}
3871
3872 5054 virtual ~Rdb_transaction() {
3873 #ifndef DEBUG_OFF
3874 5054 RDB_MUTEX_LOCK_CHECK(s_tx_list_mutex);
3875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2537 times.
5074 assert(s_tx_list.find(this) == s_tx_list.end());
3876 5074 RDB_MUTEX_UNLOCK_CHECK(s_tx_list_mutex);
3877 #endif
3878 }
3879 };
3880
3881 #ifndef NDEBUG
3882 // simulate that RocksDB has reported corrupted data
3883 static void dbug_change_status_to_corrupted(rocksdb::Status *status) {
3884 *status = rocksdb::Status::Corruption();
3885 }
3886 static void dbug_change_status_to_io_error(rocksdb::Status *status) {
3887 *status = rocksdb::Status::IOError();
3888 }
3889 static void dbug_change_status_to_incomplete(rocksdb::Status *status) {
3890 *status = rocksdb::Status::Incomplete();
3891 }
3892 #endif
3893
3894 3581134 static void fix_write_disable_wal_value(THD *thd, bool sync) {
3895 // check if we should switch back to write_disable_wal_save
3896
6/6
✓ Branch 0 taken 111194 times.
✓ Branch 1 taken 3469940 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 111300 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3581240 times.
3581134 if (!sync && THDVAR(thd, write_disable_wal_save)) {
3897 3 THDVAR(thd, write_disable_wal) = THDVAR(thd, write_disable_wal_save);
3898 3 THDVAR(thd, write_disable_wal_save) = false;
3899
8/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
3 LogPluginErrMsg(WARNING_LEVEL, 0,
3900 "Sync writes disabled. Switching back to "
3901 "rocksdb_write_disable_wal = true");
3902 }
3903
3904
6/6
✓ Branch 0 taken 3469871 times.
✓ Branch 1 taken 111372 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3469989 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3581361 times.
3581243 if (sync && THDVAR(thd, write_disable_wal)) {
3905 // write_disable_wal and write_opts.sync are not compatible
3906 // let's remember real session value of write_disable_wal
3907 // and fall back to the compatible one
3908 // We will switch back to the real session value once the global
3909 // rocksdb_flush_log_at_trx_commit is compatible again
3910 3 THDVAR(thd, write_disable_wal_save) = THDVAR(thd, write_disable_wal);
3911
3912 3 THDVAR(thd, write_disable_wal) = false;
3913
8/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
3 LogPluginErrMsg(
3914 WARNING_LEVEL, 0,
3915 "Sync writes has to enable WAL. Switching to rocksdb_write_disable_wal "
3916 "= false for the time when sync writes are enabled.");
3917 }
3918 3581364 }
3919
3920 /*
3921 This is a rocksdb transaction. Its members represent the current transaction,
3922 which consists of:
3923 - the snapshot
3924 - the changes we've made but are not seeing yet.
3925
3926 The changes are made to individual tables, which store them here and then
3927 this object commits them on commit.
3928 */
3929 class Rdb_transaction_impl : public Rdb_transaction {
3930 rocksdb::Transaction *m_rocksdb_tx = nullptr;
3931 rocksdb::Transaction *m_rocksdb_reuse_tx = nullptr;
3932
3933 public:
3934 112277455 void set_lock_timeout(int timeout_sec_arg) override {
3935
2/2
✓ Branch 0 taken 108740340 times.
✓ Branch 1 taken 3537115 times.
112277455 if (m_rocksdb_tx) {
3936 108740340 m_rocksdb_tx->SetLockTimeout(rdb_convert_sec_to_ms(timeout_sec_arg));
3937 }
3938 112232218 }
3939
3940 3432832 void set_sync(bool sync) override {
3941 3432832 m_rocksdb_tx->GetWriteOptions()->sync = sync;
3942 3432872 }
3943
3944 3607375 void release_lock(const Rdb_key_def &key_descr, const std::string &rowkey,
3945 bool force) override {
3946
5/6
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 3607327 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
✓ Branch 4 taken 3607327 times.
✓ Branch 5 taken 48 times.
3607375 if (!THDVAR(m_thd, lock_scanned_rows) || force) {
3947
1/2
✓ Branch 0 taken 3607327 times.
✗ Branch 1 not taken.
3607327 m_rocksdb_tx->UndoGetForUpdate(key_descr.get_cf(),
3948 3607327 rocksdb::Slice(rowkey));
3949 // row_lock_count track row(pk)
3950
4/6
✓ Branch 0 taken 3606763 times.
✓ Branch 1 taken 564 times.
✓ Branch 2 taken 3606763 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3606763 times.
✗ Branch 5 not taken.
3607327 assert(!key_descr.is_primary_key() ||
3951 (key_descr.is_primary_key() && m_row_lock_count > 0));
3952 // m_row_lock_count tracks per row data instead of per key data
3953
5/6
✓ Branch 0 taken 3606763 times.
✓ Branch 1 taken 564 times.
✓ Branch 2 taken 3606763 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3606763 times.
✓ Branch 5 taken 564 times.
3607327 if (key_descr.is_primary_key() && m_row_lock_count > 0) {
3954 3606763 m_row_lock_count--;
3955 }
3956 }
3957 3607375 }
3958
3959 240 virtual bool is_writebatch_trx() const override { return false; }
3960
3961 private:
3962 3581429 void release_tx(void) {
3963 // We are done with the current active transaction object. Preserve it
3964 // for later reuse.
3965
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3581429 times.
3581429 assert(m_rocksdb_reuse_tx == nullptr);
3966 3581429 m_rocksdb_reuse_tx = m_rocksdb_tx;
3967 3581429 m_rocksdb_tx = nullptr;
3968 3581429 }
3969
3970 3433389 bool prepare() override {
3971 3433389 rocksdb::Status s;
3972
3973
3/6
✓ Branch 0 taken 3433403 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3433425 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3433574 times.
✗ Branch 5 not taken.
3433469 s = merge_auto_incr_map(m_rocksdb_tx->GetWriteBatch()->GetWriteBatch());
3974 #ifndef NDEBUG
3975
2/6
✓ Branch 0 taken 3433467 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3433467 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3433596 DBUG_EXECUTE_IF("myrocks_prepare_io_error",
3976 dbug_change_status_to_io_error(&s););
3977
2/6
✓ Branch 0 taken 3433539 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3433539 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3433467 DBUG_EXECUTE_IF("myrocks_prepare_incomplete",
3978 dbug_change_status_to_incomplete(&s););
3979 #endif
3980
2/4
✓ Branch 0 taken 3433560 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3433560 times.
3433539 if (!s.ok()) {
3981 std::string msg =
3982 "RocksDB error on COMMIT (Prepare/merge): " + s.ToString();
3983 my_error(ER_INTERNAL_ERROR, MYF(0), msg.c_str());
3984 return false;
3985 }
3986
3987
1/2
✓ Branch 0 taken 3433375 times.
✗ Branch 1 not taken.
3433560 s = m_rocksdb_tx->Prepare();
3988
2/4
✓ Branch 0 taken 3433471 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3433471 times.
3433502 if (!s.ok()) {
3989 std::string msg = "RocksDB error on COMMIT (Prepare): " + s.ToString();
3990 my_error(ER_INTERNAL_ERROR, MYF(0), msg.c_str());
3991 return false;
3992 }
3993 3433471 return true;
3994 3433471 }
3995
3996 3426328 bool commit_no_binlog() override {
3997 3426328 bool res = false;
3998 3426328 rocksdb::Status s;
3999
4000
3/6
✓ Branch 0 taken 3426328 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3426328 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3426328 times.
✗ Branch 5 not taken.
3426328 s = merge_auto_incr_map(m_rocksdb_tx->GetWriteBatch()->GetWriteBatch());
4001 #ifndef NDEBUG
4002
2/6
✓ Branch 0 taken 3426328 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3426328 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3426328 DBUG_EXECUTE_IF("myrocks_commit_merge_io_error",
4003 dbug_change_status_to_io_error(&s););
4004
2/6
✓ Branch 0 taken 3426328 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3426328 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3426328 DBUG_EXECUTE_IF("myrocks_commit_merge_incomplete",
4005 dbug_change_status_to_incomplete(&s););
4006 #endif
4007
2/4
✓ Branch 0 taken 3426328 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3426328 times.
3426328 if (!s.ok()) {
4008 rdb_handle_io_error(s, RDB_IO_ERROR_TX_COMMIT);
4009 res = true;
4010 goto error;
4011 }
4012
4013
1/2
✓ Branch 0 taken 3426328 times.
✗ Branch 1 not taken.
3426328 release_snapshot();
4014
1/2
✓ Branch 0 taken 3426328 times.
✗ Branch 1 not taken.
3426328 s = m_rocksdb_tx->Commit();
4015 #ifndef NDEBUG
4016
2/6
✓ Branch 0 taken 3426328 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3426328 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3426328 DBUG_EXECUTE_IF("myrocks_commit_io_error",
4017 dbug_change_status_to_io_error(&s););
4018
2/6
✓ Branch 0 taken 3426328 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3426328 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3426328 DBUG_EXECUTE_IF("myrocks_commit_incomplete",
4019 dbug_change_status_to_incomplete(&s););
4020 #endif
4021
2/4
✓ Branch 0 taken 3426328 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3426328 times.
3426328 if (!s.ok()) {
4022 rdb_handle_io_error(s, RDB_IO_ERROR_TX_COMMIT);
4023 res = true;
4024 goto error;
4025 }
4026
4027 3426328 on_commit();
4028 3426328 error:
4029 3426328 on_rollback();
4030 /* Save the transaction object to be reused */
4031 3426328 release_tx();
4032
4033 3426328 m_write_count = 0;
4034 3426328 m_row_lock_count = 0;
4035 3426328 set_tx_read_only(false);
4036 3426328 m_rollback_only = false;
4037 3426328 return res;
4038 3426328 }
4039
4040 public:
4041 3708907 void rollback() override {
4042 3708907 on_rollback();
4043 3708858 m_write_count = 0;
4044 3708858 m_row_lock_count = 0;
4045 3708858 m_auto_incr_map.clear();
4046 3708815 m_ddl_transaction = false;
4047
2/2
✓ Branch 0 taken 155101 times.
✓ Branch 1 taken 3553714 times.
3708815 if (m_rocksdb_tx) {
4048 155101 release_snapshot();
4049 /* This will also release all of the locks: */
4050 155101 m_rocksdb_tx->Rollback();
4051
4052 /* Save the transaction object to be reused */
4053 155101 release_tx();
4054
4055 155101 set_tx_read_only(false);
4056 155101 m_rollback_only = false;
4057 }
4058 3708815 }
4059
4060 25995750 void acquire_snapshot(bool acquire_now) override {
4061
2/2
✓ Branch 0 taken 4235981 times.
✓ Branch 1 taken 21759769 times.
25995750 if (m_read_opts.snapshot == nullptr) {
4062
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 4235988 times.
4235981 if (is_tx_read_only()) {
4063 39 snapshot_created(rdb->GetSnapshot());
4064
2/2
✓ Branch 0 taken 245582 times.
✓ Branch 1 taken 3990406 times.
4235988 } else if (acquire_now) {
4065 245582 m_rocksdb_tx->SetSnapshot();
4066 245582 snapshot_created(m_rocksdb_tx->GetSnapshot());
4067
2/2
✓ Branch 0 taken 3416419 times.
✓ Branch 1 taken 573987 times.
3990406 } else if (!m_is_delayed_snapshot) {
4068
1/2
✓ Branch 0 taken 3416724 times.
✗ Branch 1 not taken.
3416419 m_rocksdb_tx->SetSnapshotOnNextOperation(m_notifier);
4069 3416746 m_is_delayed_snapshot = true;
4070 }
4071 }
4072 25996140 }
4073
4074 3712848 void release_snapshot() override {
4075 3712848 bool need_clear = m_is_delayed_snapshot;
4076
4077
2/2
✓ Branch 0 taken 3552329 times.
✓ Branch 1 taken 160519 times.
3712848 if (m_read_opts.snapshot != nullptr) {
4078 3552329 m_snapshot_timestamp = 0;
4079
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 3552273 times.
3552329 if (is_tx_read_only()) {
4080 56 rdb->ReleaseSnapshot(m_read_opts.snapshot);
4081 56 need_clear = false;
4082 } else {
4083 3552273 need_clear = true;
4084 }
4085 3552329 m_read_opts.snapshot = nullptr;
4086 }
4087
4088
3/4
✓ Branch 0 taken 3558124 times.
✓ Branch 1 taken 154724 times.
✓ Branch 2 taken 3558124 times.
✗ Branch 3 not taken.
3712848 if (need_clear && m_rocksdb_tx != nullptr) m_rocksdb_tx->ClearSnapshot();
4089 3712848 m_is_delayed_snapshot = false;
4090 3712848 }
4091
4092 bool has_snapshot() { return m_read_opts.snapshot != nullptr; }
4093
4094 7420854 rocksdb::Status put(rocksdb::ColumnFamilyHandle *const column_family,
4095 const rocksdb::Slice &key, const rocksdb::Slice &value,
4096 const bool assume_tracked) override {
4097 7420854 ++m_write_count;
4098 7420854 return m_rocksdb_tx->Put(column_family, key, value, assume_tracked);
4099 }
4100
4101 280025 rocksdb::Status delete_key(rocksdb::ColumnFamilyHandle *const column_family,
4102 const rocksdb::Slice &key,
4103 const bool assume_tracked) override {
4104 280025 ++m_write_count;
4105 280025 return m_rocksdb_tx->Delete(column_family, key, assume_tracked);
4106 }
4107
4108 104375 rocksdb::Status single_delete(
4109 rocksdb::ColumnFamilyHandle *const column_family,
4110 const rocksdb::Slice &key, const bool assume_tracked) override {
4111 104375 ++m_write_count;
4112 104375 return m_rocksdb_tx->SingleDelete(column_family, key, assume_tracked);
4113 }
4114
4115 45 bool has_modifications() const override {
4116 45 return m_rocksdb_tx->GetWriteBatch() &&
4117
2/4
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
90 m_rocksdb_tx->GetWriteBatch()->GetWriteBatch() &&
4118
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 18 times.
90 m_rocksdb_tx->GetWriteBatch()->GetWriteBatch()->Count() > 0;
4119 }
4120
4121 rocksdb::WriteBatchBase *get_write_batch() override {
4122 return m_rocksdb_tx->GetCommitTimeWriteBatch();
4123 }
4124
4125 /*
4126 Return a WriteBatch that one can write to. The writes will skip any
4127 transaction locking. The writes WILL be visible to the transaction.
4128 */
4129 52977163 rocksdb::WriteBatchBase *get_indexed_write_batch() override {
4130 52977163 ++m_write_count;
4131 52977163 return m_rocksdb_tx->GetWriteBatch();
4132 }
4133
4134 12100520 rocksdb::Status get(rocksdb::ColumnFamilyHandle *const column_family,
4135 const rocksdb::Slice &key,
4136 rocksdb::PinnableSlice *const value) const override {
4137 // clean PinnableSlice right before Get() for multiple gets per statement
4138 // the resources after the last Get in a statement are cleared in
4139 // handler::reset call
4140 12100520 value->Reset();
4141 12100520 global_stats.queries[QUERIES_POINT].inc();
4142 12100520 return m_rocksdb_tx->Get(m_read_opts, column_family, key, value);
4143 }
4144
4145 12606683 rocksdb::Status get_for_update(const Rdb_key_def &key_descr,
4146 const rocksdb::Slice &key,
4147 rocksdb::PinnableSlice *const value,
4148 bool exclusive, const bool do_validate,
4149 bool no_wait) override {
4150 12606683 rocksdb::ColumnFamilyHandle *const column_family = key_descr.get_cf();
4151 /* check row lock limit in a trx */
4152
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 12633630 times.
12608856 if (get_row_lock_count() >= get_max_row_lock_count()) {
4153
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 return rocksdb::Status::Aborted(rocksdb::Status::kLockLimit);
4154 }
4155
4156
2/2
✓ Branch 0 taken 12611246 times.
✓ Branch 1 taken 22384 times.
12633630 if (value != nullptr) {
4157
1/2
✓ Branch 0 taken 12581852 times.
✗ Branch 1 not taken.
12611246 value->Reset();
4158
5/8
✓ Branch 0 taken 12625295 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 12625292 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
12581852 DBUG_EXECUTE_IF("rocksdb_check_uniqueness",
4159 DEBUG_SYNC(m_thd, "rocksdb_after_unpin"););
4160 }
4161
4162
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 12647529 times.
12647679 if (no_wait) {
4163
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 set_lock_timeout(0);
4164 }
4165 12667899 auto restore_wait = create_scope_guard([&]() {
4166
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 12667749 times.
12667899 if (no_wait) {
4167 150 set_lock_timeout(m_timeout_sec);
4168 }
4169
1/2
✓ Branch 0 taken 12604347 times.
✗ Branch 1 not taken.
12647679 });
4170
4171 12604347 rocksdb::Status s;
4172 // If snapshot is null, pass it to GetForUpdate and snapshot is
4173 // initialized there. Snapshot validation is skipped in that case.
4174
4/4
✓ Branch 0 taken 9387954 times.
✓ Branch 1 taken 3304805 times.
✓ Branch 2 taken 6308379 times.
✓ Branch 3 taken 3079575 times.
12692759 if (m_read_opts.snapshot == nullptr || do_validate) {
4175 9660809 s = m_rocksdb_tx->GetForUpdate(
4176
1/2
✓ Branch 0 taken 9622438 times.
✗ Branch 1 not taken.
9613184 m_read_opts, column_family, key, value, exclusive,
4177
4/4
✓ Branch 0 taken 6301383 times.
✓ Branch 1 taken 3311801 times.
✓ Branch 2 taken 6294626 times.
✓ Branch 3 taken 6757 times.
19235622 m_read_opts.snapshot ? do_validate : false);
4178 } else {
4179 // If snapshot is set, and if skipping validation,
4180 // call GetForUpdate without validation and set back old snapshot
4181 3079575 auto saved_snapshot = m_read_opts.snapshot;
4182 3079575 m_read_opts.snapshot = nullptr;
4183
1/2
✓ Branch 0 taken 3079575 times.
✗ Branch 1 not taken.
6159150 s = m_rocksdb_tx->GetForUpdate(m_read_opts, column_family, key, value,
4184 3079575 exclusive, false);
4185 3079575 m_read_opts.snapshot = saved_snapshot;
4186 }
4187
4188 // row_lock_count is to track per row instead of per key
4189
2/2
✓ Branch 0 taken 12642302 times.
✓ Branch 1 taken 49320 times.
12734122 if (key_descr.is_primary_key()) incr_row_lock_count();
4190 12676649 return s;
4191 12739036 }
4192
4193 259898 rocksdb::Iterator *get_iterator(
4194 const rocksdb::ReadOptions &options,
4195 rocksdb::ColumnFamilyHandle *const column_family) override {
4196 259898 global_stats.queries[QUERIES_RANGE].inc();
4197 259898 return m_rocksdb_tx->GetIterator(options, column_family);
4198 }
4199
4200 240 const rocksdb::Transaction *get_rdb_trx() const { return m_rocksdb_tx; }
4201
4202 116107992 bool is_tx_started() const override { return (m_rocksdb_tx != nullptr); }
4203
4204 3580990 void start_tx() override {
4205 3580990 rocksdb::TransactionOptions tx_opts;
4206 3580990 rocksdb::WriteOptions write_opts;
4207 3580985 tx_opts.set_snapshot = false;
4208
1/2
✓ Branch 0 taken 3581116 times.
✗ Branch 1 not taken.
3580985 tx_opts.lock_timeout = rdb_convert_sec_to_ms(m_timeout_sec);
4209
1/2
✓ Branch 0 taken 3581254 times.
✗ Branch 1 not taken.
3581116 tx_opts.deadlock_detect = THDVAR(m_thd, deadlock_detect);
4210
1/2
✓ Branch 0 taken 3581308 times.
✗ Branch 1 not taken.
3581254 tx_opts.deadlock_detect_depth = THDVAR(m_thd, deadlock_detect_depth);
4211 // If this variable is set, this will write commit time write batch
4212 // information on recovery or memtable flush.
4213 3581383 tx_opts.use_only_the_last_commit_time_batch_for_recovery =
4214
1/2
✓ Branch 0 taken 3581383 times.
✗ Branch 1 not taken.
3581308 THDVAR(m_thd, commit_time_batch_for_recovery);
4215
1/2
✓ Branch 0 taken 3581212 times.
✗ Branch 1 not taken.
3581383 tx_opts.max_write_batch_size = THDVAR(m_thd, write_batch_max_bytes);
4216 3581221 tx_opts.write_batch_flush_threshold =
4217
1/2
✓ Branch 0 taken 3581221 times.
✗ Branch 1 not taken.
3581212 THDVAR(m_thd, write_batch_flush_threshold);
4218
4219
2/2
✓ Branch 0 taken 3470010 times.
✓ Branch 1 taken 111211 times.
7051079 write_opts.sync = (rocksdb_flush_log_at_trx_commit == FLUSH_LOG_SYNC) &&
4220
2/4
✓ Branch 0 taken 3469858 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3469971 times.
✗ Branch 3 not taken.
3470010 rdb_sync_wal_supported();
4221
1/2
✓ Branch 0 taken 3581032 times.
✗ Branch 1 not taken.
3581069 fix_write_disable_wal_value(m_thd, write_opts.sync);
4222
1/2
✓ Branch 0 taken 3581244 times.
✗ Branch 1 not taken.
3581032 write_opts.disableWAL = THDVAR(m_thd, write_disable_wal);
4223 3581296 write_opts.ignore_missing_column_families =
4224
1/2
✓ Branch 0 taken 3581296 times.
✗ Branch 1 not taken.
3581244 THDVAR(m_thd, write_ignore_missing_column_families);
4225
4226 /*
4227 If m_rocksdb_reuse_tx is null this will create a new transaction object.
4228 Otherwise it will reuse the existing one.
4229 */
4230 3580820 m_rocksdb_tx =
4231
1/2
✓ Branch 0 taken 3580820 times.
✗ Branch 1 not taken.
3581296 rdb->BeginTransaction(write_opts, tx_opts, m_rocksdb_reuse_tx);
4232 3580820 m_rocksdb_reuse_tx = nullptr;
4233
4234
1/2
✓ Branch 0 taken 3580696 times.
✗ Branch 1 not taken.
3580820 m_read_opts = rocksdb::ReadOptions();
4235
4236
1/2
✓ Branch 0 taken 3580759 times.
✗ Branch 1 not taken.
3581287 set_initial_savepoint();
4237
4238 3580759 m_ddl_transaction = false;
4239 3580759 m_is_delayed_snapshot = false;
4240 3580759 }
4241
4242 3613523 void set_name() override {
4243 3613523 XID xid;
4244
1/2
✓ Branch 0 taken 3613620 times.
✗ Branch 1 not taken.
3613403 thd_get_xid(m_thd, reinterpret_cast<MYSQL_XID *>(&xid));
4245
1/2
✓ Branch 0 taken 3613622 times.
✗ Branch 1 not taken.
3613620 auto name = m_rocksdb_tx->GetName();
4246
2/2
✓ Branch 0 taken 132382 times.
✓ Branch 1 taken 3481129 times.
3613622 if (!name.empty()) {
4247
2/4
✓ Branch 0 taken 132382 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 132382 times.
132382 assert(name == rdb_xid_to_string(xid));
4248 132382 return;
4249 }
4250
2/4
✓ Branch 0 taken 3481170 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3481734 times.
✗ Branch 3 not taken.
3481129 rocksdb::Status s = m_rocksdb_tx->SetName(rdb_xid_to_string(xid));
4251
2/4
✓ Branch 0 taken 3481751 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3481751 times.
3481751 assert(s.ok());
4252
2/4
✓ Branch 0 taken 3481751 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3481751 times.
3481751 if (!s.ok()) {
4253 rdb_handle_io_error(s, RDB_IO_ERROR_TX_COMMIT);
4254 }
4255
2/2
✓ Branch 0 taken 3481751 times.
✓ Branch 1 taken 132382 times.
3614133 }
4256
4257 /* Implementations of do_*savepoint based on rocksdB::Transaction savepoints
4258 */
4259 3630175 void do_set_savepoint() override { m_rocksdb_tx->SetSavePoint(); }
4260 98892 rocksdb::Status do_pop_savepoint() override {
4261 98892 return m_rocksdb_tx->PopSavePoint();
4262 }
4263
4264 138 void do_rollback_to_savepoint() override {
4265 138 m_rocksdb_tx->RollbackToSavePoint();
4266 138 }
4267
4268 /*
4269 Start a statement inside a multi-statement transaction.
4270
4271 @todo: are we sure this is called once (and not several times) per
4272 statement start?
4273
4274 For hooking to start of statement that is its own transaction, see
4275 ha_rocksdb::external_lock().
4276 */
4277 417920 void start_stmt() override {
4278 // Set the snapshot to delayed acquisition (SetSnapshotOnNextOperation)
4279 417920 acquire_snapshot(false);
4280 417920 }
4281
4282 /*
4283 This must be called when last statement is rolled back, but the transaction
4284 continues
4285 */
4286 3458 void rollback_stmt() override {
4287 /* TODO: here we must release the locks taken since the start_stmt() call */
4288
2/2
✓ Branch 0 taken 3386 times.
✓ Branch 1 taken 72 times.
3458 if (m_rocksdb_tx) {
4289 3386 const rocksdb::Snapshot *const org_snapshot = m_rocksdb_tx->GetSnapshot();
4290 3386 rollback_to_stmt_savepoint();
4291
4292 3386 const rocksdb::Snapshot *const cur_snapshot = m_rocksdb_tx->GetSnapshot();
4293
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 3258 times.
3386 if (org_snapshot != cur_snapshot) {
4294
1/2
✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
128 if (org_snapshot != nullptr) m_snapshot_timestamp = 0;
4295
4296 128 m_read_opts.snapshot = cur_snapshot;
4297
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 112 times.
128 if (cur_snapshot != nullptr) {
4298 16 rdb->GetEnv()->GetCurrentTime(&m_snapshot_timestamp);
4299 } else {
4300
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 m_rocksdb_tx->SetSnapshotOnNextOperation(m_notifier);
4301 112 m_is_delayed_snapshot = true;
4302 }
4303 }
4304 }
4305 3458 }
4306
4307 2569 explicit Rdb_transaction_impl(THD *const thd)
4308 2569 : Rdb_transaction(thd), m_rocksdb_tx(nullptr) {
4309 // Create a notifier that can be called when a snapshot gets generated.
4310
1/2
✓ Branch 0 taken 2568 times.
✗ Branch 1 not taken.
2568 m_notifier = std::make_shared<Rdb_snapshot_notifier>(this);
4311 2565 }
4312
4313 10100 virtual ~Rdb_transaction_impl() override {
4314 // Remove from the global list before all other processing is started.
4315 // Otherwise, information_schema.rocksdb_trx can crash on this object.
4316 5050 Rdb_transaction::remove_from_global_trx_list();
4317
4318 5054 rollback();
4319
4320 // Theoretically the notifier could outlive the Rdb_transaction_impl
4321 // (because of the shared_ptr), so let it know it can't reference
4322 // the transaction anymore.
4323 5054 m_notifier->detach();
4324
4325 // Free any transaction memory that is still hanging around.
4326
1/2
✓ Branch 0 taken 2527 times.
✗ Branch 1 not taken.
5054 delete m_rocksdb_reuse_tx;
4327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2527 times.
5054 assert(m_rocksdb_tx == nullptr);
4328 10104 }
4329 };
4330
4331 /* This is a rocksdb write batch. This class doesn't hold or wait on any
4332 transaction locks (skips rocksdb transaction API) thus giving better
4333 performance.
4334
4335 Currently this is only used for replication threads which are guaranteed
4336 to be non-conflicting. Any further usage of this class should completely
4337 be thought thoroughly.
4338 */
4339 class Rdb_writebatch_impl : public Rdb_transaction {
4340 rocksdb::WriteBatchWithIndex *m_batch;
4341 rocksdb::WriteOptions write_opts;
4342 // Called after commit/rollback.
4343 6024 void reset() {
4344 6024 m_batch->Clear();
4345 6024 m_read_opts = rocksdb::ReadOptions();
4346 6024 m_ddl_transaction = false;
4347 6024 }
4348
4349 private:
4350 6002 bool prepare() override { return true; }
4351
4352 6002 bool commit_no_binlog() override {
4353 6002 bool res = false;
4354 6002 rocksdb::Status s;
4355 6002 rocksdb::TransactionDBWriteOptimizations optimize;
4356 6002 optimize.skip_concurrency_control = true;
4357
4358
2/4
✓ Branch 0 taken 6002 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6002 times.
✗ Branch 3 not taken.
6002 s = merge_auto_incr_map(m_batch->GetWriteBatch());
4359
2/4
✓ Branch 0 taken 6002 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6002 times.
6002 if (!s.ok()) {
4360 rdb_handle_io_error(s, RDB_IO_ERROR_TX_COMMIT);
4361 res = true;
4362 goto error;
4363 }
4364
4365
1/2
✓ Branch 0 taken 6002 times.
✗ Branch 1 not taken.
6002 release_snapshot();
4366
4367
2/4
✓ Branch 0 taken 6002 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6002 times.
✗ Branch 3 not taken.
6002 s = rdb->Write(write_opts, optimize, m_batch->GetWriteBatch());
4368
2/4
✓ Branch 0 taken 6002 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6002 times.
6002 if (!s.ok()) {
4369 rdb_handle_io_error(s, RDB_IO_ERROR_TX_COMMIT);
4370 res = true;
4371 goto error;
4372 }
4373 6002 on_commit();
4374 6002 error:
4375 6002 on_rollback();
4376
1/2
✓ Branch 0 taken 6002 times.
✗ Branch 1 not taken.
6002 reset();
4377
4378 6002 m_write_count = 0;
4379 6002 set_tx_read_only(false);
4380 6002 m_rollback_only = false;
4381 6002 return res;
4382 6002 }
4383
4384 /* Implementations of do_*savepoint based on rocksdB::WriteBatch savepoints */
4385 20 void do_set_savepoint() override { m_batch->SetSavePoint(); }
4386 20 rocksdb::Status do_pop_savepoint() override {
4387 20 return m_batch->PopSavePoint();
4388 }
4389
4390 void do_rollback_to_savepoint() override { m_batch->RollbackToSavePoint(); }
4391
4392 public:
4393 6 bool is_writebatch_trx() const override { return true; }
4394
4395 18026 void set_lock_timeout(int timeout_sec_arg) override {
4396 // Nothing to do here.
4397 18026 }
4398
4399 6002 void set_sync(bool sync) override { write_opts.sync = sync; }
4400
4401 void release_lock(const Rdb_key_def &key_descr, const std::string &rowkey,
4402 bool force) override {
4403 // Nothing to do here since we don't hold any row locks.
4404 }
4405
4406 12 void rollback() override {
4407 12 on_rollback();
4408 12 m_write_count = 0;
4409 12 m_row_lock_count = 0;
4410 12 release_snapshot();
4411
4412 12 reset();
4413 12 set_tx_read_only(false);
4414 12 m_rollback_only = false;
4415 12 }
4416
4417 6010 void acquire_snapshot(bool acquire_now) override {
4418
2/2
✓ Branch 0 taken 6004 times.
✓ Branch 1 taken 6 times.
6010 if (m_read_opts.snapshot == nullptr) snapshot_created(rdb->GetSnapshot());
4419 6010 }
4420
4421 18014 void release_snapshot() override {
4422
2/2
✓ Branch 0 taken 6004 times.
✓ Branch 1 taken 12010 times.
18014 if (m_read_opts.snapshot != nullptr) {
4423 6004 rdb->ReleaseSnapshot(m_read_opts.snapshot);
4424 6004 m_read_opts.snapshot = nullptr;
4425 }
4426 18014 }
4427
4428 6010 rocksdb::Status put(rocksdb::ColumnFamilyHandle *const column_family,
4429 const rocksdb::Slice &key, const rocksdb::Slice &value,
4430 const bool assume_tracked) override {
4431 6010 ++m_write_count;
4432 6010 m_batch->Put(column_family, key, value);
4433 // Note Put/Delete in write batch doesn't return any error code. We simply
4434 // return OK here.
4435 6010 return rocksdb::Status::OK();
4436 }
4437
4438 rocksdb::Status delete_key(rocksdb::ColumnFamilyHandle *const column_family,
4439 const rocksdb::Slice &key,
4440 const bool assume_tracked) override {
4441 ++m_write_count;
4442 m_batch->Delete(column_family, key);
4443 return rocksdb::Status::OK();
4444 }
4445
4446 rocksdb::Status single_delete(
4447 rocksdb::ColumnFamilyHandle *const column_family,
4448 const rocksdb::Slice &key, const bool assume_tracked) override {
4449 ++m_write_count;
4450 m_batch->SingleDelete(column_family, key);
4451 return rocksdb::Status::OK();
4452 }
4453
4454 bool has_modifications() const override {
4455 return m_batch->GetWriteBatch()->Count() > 0;
4456 }
4457
4458 rocksdb::WriteBatchBase *get_write_batch() override { return m_batch; }
4459
4460 3000 rocksdb::WriteBatchBase *get_indexed_write_batch() override {
4461 3000 ++m_write_count;
4462 3000 return m_batch;
4463 }
4464
4465 9010 rocksdb::Status get(rocksdb::ColumnFamilyHandle *const column_family,
4466 const rocksdb::Slice &key,
4467 rocksdb::PinnableSlice *const value) const override {
4468 9010 value->Reset();
4469 9010 return m_batch->GetFromBatchAndDB(rdb, m_read_opts, column_family, key,
4470 9010 value);
4471 }
4472
4473 9010 rocksdb::Status get_for_update(const Rdb_key_def &key_descr,
4474 const rocksdb::Slice &key,
4475 rocksdb::PinnableSlice *const value,
4476 bool /* exclusive */,
4477 const bool /* do_validate */,
4478 bool /* no_wait */) override {
4479 9010 rocksdb::ColumnFamilyHandle *const column_family = key_descr.get_cf();
4480
2/2
✓ Branch 0 taken 3000 times.
✓ Branch 1 taken 6010 times.
9010 if (value == nullptr) {
4481
1/2
✓ Branch 0 taken 3000 times.
✗ Branch 1 not taken.
3000 rocksdb::PinnableSlice pin_val;
4482
1/2
✓ Branch 0 taken 3000 times.
✗ Branch 1 not taken.
3000 rocksdb::Status s = get(column_family, key, &pin_val);
4483
1/2
✓ Branch 0 taken 3000 times.
✗ Branch 1 not taken.
3000 pin_val.Reset();
4484 3000 return s;
4485 3000 }
4486
4487 6010 return get(column_family, key, value);
4488 }
4489
4490 3000 rocksdb::Iterator *get_iterator(
4491 const rocksdb::ReadOptions &options,
4492 rocksdb::ColumnFamilyHandle *const column_family) override {
4493 3000 const auto it = rdb->NewIterator(options);
4494 3000 return m_batch->NewIteratorWithBase(it);
4495 }
4496
4497 30022 bool is_tx_started() const override { return (m_batch != nullptr); }
4498
4499 10 void start_tx() override {
4500 10 reset();
4501
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
20 write_opts.sync = (rocksdb_flush_log_at_trx_commit == FLUSH_LOG_SYNC) &&
4502
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 rdb_sync_wal_supported();
4503
4504 10 fix_write_disable_wal_value(m_thd, write_opts.sync);
4505 10 write_opts.disableWAL = THDVAR(m_thd, write_disable_wal);
4506 10 write_opts.ignore_missing_column_families =
4507 10 THDVAR(m_thd, write_ignore_missing_column_families);
4508
4509 10 set_initial_savepoint();
4510 10 }
4511
4512 6002 void set_name() override {}
4513
4514 6006 void start_stmt() override {}
4515
4516 void rollback_stmt() override {
4517 if (m_batch) rollback_to_stmt_savepoint();
4518 }
4519
4520 10 explicit Rdb_writebatch_impl(THD *const thd)
4521 10 : Rdb_transaction(thd), m_batch(nullptr) {
4522
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 m_batch = new rocksdb::WriteBatchWithIndex(rocksdb::BytewiseComparator(), 0,
4523
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 true);
4524 10 }
4525
4526 40 virtual ~Rdb_writebatch_impl() override {
4527 // Remove from the global list before all other processing is started.
4528 // Otherwise, information_schema.rocksdb_trx can crash on this object.
4529 20 Rdb_transaction::remove_from_global_trx_list();
4530
4531 20 rollback();
4532
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
20 delete m_batch;
4533 40 }
4534 };
4535
4536 3306638 void Rdb_snapshot_notifier::SnapshotCreated(
4537 const rocksdb::Snapshot *const snapshot) {
4538
1/2
✓ Branch 0 taken 3306653 times.
✗ Branch 1 not taken.
3306638 if (m_owning_tx != nullptr) {
4539 3306653 m_owning_tx->snapshot_created(snapshot);
4540 }
4541 3306732 }
4542
4543 std::multiset<Rdb_transaction *> Rdb_transaction::s_tx_list;
4544 Rds_mysql_mutex Rdb_transaction::s_tx_list_mutex;
4545
4546 class Rdb_ha_data {
4547 public:
4548 2590 Rdb_ha_data()
4549 2590 : checkpoint_dir(nullptr), trx(nullptr), disable_file_deletions(false) {}
4550
4551 2541 ~Rdb_ha_data() { clear_checkpoint_dir(); }
4552
4553 2548 const char *get_checkpoint_dir() const { return checkpoint_dir; }
4554
4555 6 void set_checkpoint_dir(const char *checkpoint_dir_) {
4556 6 clear_checkpoint_dir();
4557
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (checkpoint_dir_ != nullptr) {
4558 3 checkpoint_dir = strdup(checkpoint_dir_);
4559 }
4560 6 }
4561
4562 335596922 Rdb_transaction *get_trx() const { return trx; }
4563
4564 5110 void set_trx(Rdb_transaction *t) { trx = t; }
4565
4566 2557 bool get_disable_file_deletions() const { return disable_file_deletions; }
4567
4568 11 void set_disable_file_deletions(bool d) { disable_file_deletions = d; }
4569
4570 private:
4571 2548 void clear_checkpoint_dir() {
4572
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2545 times.
2548 if (checkpoint_dir) {
4573 3 free(checkpoint_dir);
4574 3 checkpoint_dir = nullptr;
4575 }
4576 2548 }
4577
4578 private:
4579 char *checkpoint_dir;
4580 Rdb_transaction *trx;
4581 bool disable_file_deletions;
4582 };
4583
4584 335400764 static Rdb_ha_data *&get_ha_data(THD *const thd) {
4585 Rdb_ha_data **ha_data =
4586 335400764 reinterpret_cast<Rdb_ha_data **>(my_core::thd_ha_data(thd, rocksdb_hton));
4587
2/2
✓ Branch 0 taken 2590 times.
✓ Branch 1 taken 335623486 times.
335626076 if (*ha_data == nullptr) {
4588 2590 *ha_data = new Rdb_ha_data();
4589 }
4590 335587704 return *ha_data;
4591 }
4592
4593 2543 static void destroy_ha_data(THD *const thd) {
4594 2543 Rdb_ha_data *&ha_data = get_ha_data(thd);
4595
1/2
✓ Branch 0 taken 2548 times.
✗ Branch 1 not taken.
2548 delete ha_data;
4596 2547 ha_data = nullptr;
4597 2547 }
4598
4599 335379979 Rdb_transaction *get_tx_from_thd(THD *const thd) {
4600 335379979 return get_ha_data(thd)->get_trx();
4601 }
4602
4603 5108 static void set_tx_on_thd(THD *const thd, Rdb_transaction *trx) {
4604 5108 return get_ha_data(thd)->set_trx(trx);
4605 }
4606
4607 class Rdb_perf_context_guard {
4608 Rdb_io_perf m_io_perf;
4609 Rdb_io_perf *m_io_perf_ptr;
4610 Rdb_transaction *m_tx;
4611 uint m_level;
4612
4613 public:
4614 Rdb_perf_context_guard(const Rdb_perf_context_guard &) = delete;
4615 Rdb_perf_context_guard &operator=(const Rdb_perf_context_guard &) = delete;
4616
4617 24016 explicit Rdb_perf_context_guard(Rdb_io_perf *io_perf, uint level)
4618 24016 : m_io_perf_ptr(io_perf), m_tx(nullptr), m_level(level) {
4619 24016 m_io_perf_ptr->start(m_level);
4620 24016 }
4621
4622 4008331 explicit Rdb_perf_context_guard(Rdb_transaction *tx, uint level)
4623 4008331 : m_io_perf_ptr(nullptr), m_tx(tx), m_level(level) {
4624 /*
4625 if perf_context information is already being recorded, this becomes a
4626 no-op
4627 */
4628
1/2
✓ Branch 0 taken 4008331 times.
✗ Branch 1 not taken.
4008331 if (tx != nullptr) {
4629 4008331 tx->io_perf_start(&m_io_perf);
4630 }
4631 4008331 }
4632
4633 4032347 ~Rdb_perf_context_guard() {
4634
2/2
✓ Branch 0 taken 4008331 times.
✓ Branch 1 taken 24016 times.
4032347 if (m_tx != nullptr) {
4635 4008331 m_tx->io_perf_end_and_record();
4636
1/2
✓ Branch 0 taken 24016 times.
✗ Branch 1 not taken.
24016 } else if (m_io_perf_ptr != nullptr) {
4637 24016 m_io_perf_ptr->end_and_record(m_level);
4638 }
4639 4032347 }
4640 };
4641
4642 /*
4643 TODO: maybe, call this in external_lock() and store in ha_rocksdb..
4644 */
4645
4646 112236955 static Rdb_transaction *get_or_create_tx(THD *const thd) {
4647 112236955 Rdb_transaction *tx = get_tx_from_thd(thd);
4648 // TODO: this is called too many times.. O(#rows)
4649
2/2
✓ Branch 0 taken 2579 times.
✓ Branch 1 taken 112375043 times.
112377622 if (tx == nullptr) {
4650
6/6
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2568 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 2569 times.
5148 if ((rpl_skip_tx_api_var && thd->rli_slave) ||
4651
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2569 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2569 (THDVAR(thd, master_skip_tx_api) && !thd->rli_slave)) {
4652
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 tx = new Rdb_writebatch_impl(thd);
4653 } else {
4654
1/2
✓ Branch 0 taken 2567 times.
✗ Branch 1 not taken.
2569 tx = new Rdb_transaction_impl(thd);
4655 }
4656 2577 tx->set_params(THDVAR(thd, lock_wait_timeout), rocksdb_max_row_locks);
4657 2576 tx->start_tx();
4658 2576 set_tx_on_thd(thd, tx);
4659
4660 // Add the transaction to the global list of transactions
4661 // once it is fully constructed.
4662 2578 tx->add_to_global_trx_list();
4663 } else {
4664 112375043 tx->set_params(THDVAR(thd, lock_wait_timeout), rocksdb_max_row_locks);
4665
2/2
✓ Branch 0 taken 3577981 times.
✓ Branch 1 taken 108716128 times.
112300426 if (!tx->is_tx_started()) {
4666 3577981 tx->start_tx();
4667 }
4668 }
4669
4670 112299768 return tx;
4671 }
4672
4673 2547 static int rocksdb_close_connection(handlerton *const hton, THD *const thd) {
4674 2547 Rdb_transaction *tx = get_tx_from_thd(thd);
4675
2/2
✓ Branch 0 taken 2537 times.
✓ Branch 1 taken 11 times.
2548 if (tx != nullptr) {
4676 bool is_critical_error;
4677
1/2
✓ Branch 0 taken 2535 times.
✗ Branch 1 not taken.
2537 int rc = tx->finish_bulk_load(&is_critical_error, false);
4678
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2532 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
2535 if (rc != 0 && is_critical_error) {
4679
9/18
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LogPluginErrMsg(ERROR_LEVEL, 0,
4680 "Error %d finalizing last SST file while disconnecting",
4681 rc);
4682 }
4683
4684
1/2
✓ Branch 0 taken 2535 times.
✗ Branch 1 not taken.
2535 delete tx;
4685
1/2
✓ Branch 0 taken 2534 times.
✗ Branch 1 not taken.
2534 set_tx_on_thd(thd, nullptr);
4686 }
4687 2545 const char *checkpoint_dir = get_ha_data(thd)->get_checkpoint_dir();
4688
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2541 times.
2543 if (checkpoint_dir != nullptr) {
4689 2 rocksdb_remove_checkpoint(checkpoint_dir);
4690 2 get_ha_data(thd)->set_checkpoint_dir(nullptr);
4691 }
4692
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2540 times.
2543 if (get_ha_data(thd)->get_disable_file_deletions()) {
4693 3 rdb->EnableFileDeletions(false);
4694 }
4695 2543 destroy_ha_data(thd);
4696 2548 return HA_EXIT_SUCCESS;
4697 }
4698
4699 6 static int rocksdb_create_temporary_checkpoint_validate(
4700 my_core::THD *const thd, my_core::SYS_VAR *const /* unused */,
4701 void *const save, my_core::st_mysql_value *const value) {
4702
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 assert(rdb != nullptr);
4703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 assert(thd != nullptr);
4704
4705 char buf[FN_REFLEN];
4706 6 int len = sizeof(buf);
4707
4708
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 const char *current_checkpoint_dir = get_ha_data(thd)->get_checkpoint_dir();
4709
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 const char *new_checkpoint_dir = value->val_str(value, buf, &len);
4710
4711
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
6 if (current_checkpoint_dir != nullptr && new_checkpoint_dir != nullptr) {
4712 1 *reinterpret_cast<const char **>(save) = current_checkpoint_dir;
4713
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_error(
4714 ER_GET_ERRMSG, MYF(0), HA_ERR_ROCKSDB_STATUS_INVALID_ARGUMENT,
4715 "Invalid argument: Temporary checkpoint already exists for session",
4716 rocksdb_hton_name);
4717 1 return HA_EXIT_FAILURE;
4718
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 } else if (new_checkpoint_dir != nullptr) {
4719
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 const auto res = rocksdb_create_checkpoint(new_checkpoint_dir);
4720
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (res == HA_EXIT_SUCCESS) {
4721 3 *reinterpret_cast<const char **>(save) = new_checkpoint_dir;
4722
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 get_ha_data(thd)->set_checkpoint_dir(new_checkpoint_dir);
4723 } else {
4724 1 return res;
4725 }
4726
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (current_checkpoint_dir != nullptr) {
4727
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 const auto res = rocksdb_remove_checkpoint(current_checkpoint_dir);
4728 1 *reinterpret_cast<const char **>(save) = nullptr;
4729
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 get_ha_data(thd)->set_checkpoint_dir(nullptr);
4730
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (res != HA_EXIT_SUCCESS) {
4731 return res;
4732 }
4733 } else {
4734 *reinterpret_cast<const char **>(save) = nullptr;
4735 get_ha_data(thd)->set_checkpoint_dir(nullptr);
4736 }
4737 4 return HA_EXIT_SUCCESS;
4738 }
4739
4740 15 static void rocksdb_disable_file_deletions_update(
4741 my_core::THD *const thd, my_core::SYS_VAR *const /* unused */,
4742 void *const var_ptr, const void *const save) {
4743
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 assert(rdb != nullptr);
4744
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 assert(thd != nullptr);
4745
4746 15 bool val = *static_cast<bool *>(var_ptr) = *static_cast<const bool *>(save);
4747
6/6
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 8 times.
15 if (val && !get_ha_data(thd)->get_disable_file_deletions()) {
4748 7 rdb->DisableFileDeletions();
4749 7 get_ha_data(thd)->set_disable_file_deletions(true);
4750
6/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
8 } else if (!val && get_ha_data(thd)->get_disable_file_deletions()) {
4751 4 rdb->EnableFileDeletions(false);
4752 4 get_ha_data(thd)->set_disable_file_deletions(false);
4753 }
4754 15 }
4755
4756 /**
4757 Called by hton->flush_logs after MySQL group commit prepares a set of
4758 transactions.
4759 */
4760 3460233 static bool rocksdb_flush_wal(handlerton *const hton MY_ATTRIBUTE((__unused__)),
4761 bool binlog_group_flush) {
4762
1/2
✓ Branch 0 taken 3460233 times.
✗ Branch 1 not taken.
3460233 DBUG_ENTER("rocksdb_flush_wal");
4763
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3460233 times.
3460233 assert(rdb != nullptr);
4764
4765 /**
4766 If !binlog_group_flush, we got invoked by FLUSH LOGS or similar.
4767 Else, we got invoked by binlog group commit during flush stage.
4768 */
4769
4770
2/2
✓ Branch 0 taken 3454473 times.
✓ Branch 1 taken 5760 times.
3460233 if (binlog_group_flush &&
4771
2/2
✓ Branch 0 taken 93137 times.
✓ Branch 1 taken 3361336 times.
3454473 rocksdb_flush_log_at_trx_commit == FLUSH_LOG_NEVER) {
4772 /**
4773 rocksdb_flush_log_at_trx_commit=0
4774 (write and sync based on timer in Rdb_background_thread).
4775 Do not flush the redo log during binlog group commit.
4776 */
4777
1/2
✓ Branch 0 taken 93137 times.
✗ Branch 1 not taken.
93137 DBUG_RETURN(false);
4778 }
4779
4780
4/6
✓ Branch 0 taken 3361336 times.
✓ Branch 1 taken 5760 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3361336 times.
✓ Branch 4 taken 3367096 times.
✗ Branch 5 not taken.
3367096 if (!binlog_group_flush || !rocksdb_db_options->allow_mmap_writes ||
4781 rocksdb_flush_log_at_trx_commit != FLUSH_LOG_NEVER) {
4782 /**
4783 Sync the WAL if we are in FLUSH LOGS, or if
4784 rocksdb_flush_log_at_trx_commit=1
4785 (write and sync at each commit).
4786 */
4787 3367096 rocksdb_wal_group_syncs++;
4788
2/4
✓ Branch 0 taken 3367096 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3367096 times.
✗ Branch 3 not taken.
6734192 bool sync = rdb_sync_wal_supported() &&
4789
2/2
✓ Branch 0 taken 3361336 times.
✓ Branch 1 taken 5760 times.
3367096 (!binlog_group_flush ||
4790
2/2
✓ Branch 0 taken 3357475 times.
✓ Branch 1 taken 3861 times.
3361336 rocksdb_flush_log_at_trx_commit == FLUSH_LOG_SYNC);
4791
1/2
✓ Branch 0 taken 3367096 times.
✗ Branch 1 not taken.
3367096 const rocksdb::Status s = rdb->FlushWAL(sync);
4792
4793
2/4
✓ Branch 0 taken 3367096 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3367096 times.
3367096 if (!s.ok()) {
4794 rdb_log_status_error(s);
4795 DBUG_RETURN(true);
4796 }
4797
1/2
✓ Branch 0 taken 3367096 times.
✗ Branch 1 not taken.
3367096 }
4798
4799
1/2
✓ Branch 0 taken 3367096 times.
✗ Branch 1 not taken.
3367096 DBUG_RETURN(false);
4800 }
4801
4802 /**
4803 For a slave, prepare() updates the slave_gtid_info table which tracks the
4804 replication progress.
4805 */
4806 3854871 static int rocksdb_prepare(handlerton *const hton, THD *const thd,
4807 bool prepare_tx) {
4808 3854871 Rdb_transaction *tx = get_tx_from_thd(thd);
4809
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3854953 times.
3855205 if (!tx->is_tx_started()) {
4810 // nothing to prepare
4811 return HA_EXIT_SUCCESS;
4812 }
4813
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 3854716 times.
3854953 if (!tx->can_prepare()) {
4814 27 return HA_EXIT_FAILURE;
4815 }
4816
4/4
✓ Branch 0 taken 3825824 times.
✓ Branch 1 taken 28892 times.
✓ Branch 2 taken 3439013 times.
✓ Branch 3 taken 415641 times.
7680478 if (prepare_tx ||
4817
2/2
✓ Branch 0 taken 3410014 times.
✓ Branch 1 taken 415748 times.
3825824 (!my_core::thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
4818
1/2
✓ Branch 0 taken 3439053 times.
✗ Branch 1 not taken.
3439013 if (thd->durability_property == HA_IGNORE_DURABILITY) {
4819 3439053 tx->set_sync(false);
4820 }
4821 // For write unprepared, set_name is called at the start of a transaction.
4822
2/2
✓ Branch 0 taken 2316366 times.
✓ Branch 1 taken 1122469 times.
3438835 if (rocksdb_write_policy != rocksdb::TxnDBWritePolicy::WRITE_UNPREPARED) {
4823 2316366 tx->set_name();
4824 }
4825
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3439406 times.
3439349 if (!tx->prepare()) {
4826 return HA_EXIT_FAILURE;
4827 }
4828
4829
1/2
✓ Branch 0 taken 3439393 times.
✗ Branch 1 not taken.
3439406 DEBUG_SYNC(thd, "rocksdb.prepared");
4830 } else
4831 415641 tx->make_stmt_savepoint_permanent();
4832
4833 3855370 return HA_EXIT_SUCCESS;
4834 }
4835
4836 23 static xa_status_code rocksdb_commit_by_xid(handlerton *const hton,
4837 XID *const xid) {
4838
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 DBUG_ENTER_FUNC();
4839
4840
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 assert(hton != nullptr);
4841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 assert(xid != nullptr);
4842
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 assert(commit_latency_stats != nullptr);
4843
4844
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 auto clock = rocksdb::Env::Default()->GetSystemClock().get();
4845
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 rocksdb::StopWatchNano timer(clock, true);
4846
4847
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 const auto name = rdb_xid_to_string(*xid);
4848
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 assert(!name.empty());
4849
4850
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 rocksdb::Transaction *const trx = rdb->GetTransactionByName(name);
4851
4852
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (trx == nullptr) {
4853 DBUG_RETURN(XAER_NOTA);
4854 }
4855
4856
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 const rocksdb::Status s = trx->Commit();
4857
4858
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
23 if (!s.ok()) {
4859 rdb_log_status_error(s);
4860 DBUG_RETURN(XAER_RMERR);
4861 }
4862
4863
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 delete trx;
4864
4865 // `Add()` is implemented in a thread-safe manner.
4866
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 commit_latency_stats->Add(timer.ElapsedNanos() / 1000);
4867
4868
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 DBUG_RETURN(XA_OK);
4869 23 }
4870
4871 static xa_status_code rocksdb_rollback_by_xid(
4872 handlerton *const hton MY_ATTRIBUTE((__unused__)), XID *const xid) {
4873 DBUG_ENTER_FUNC();
4874
4875 assert(hton != nullptr);
4876 assert(xid != nullptr);
4877 assert(rdb != nullptr);
4878
4879 const auto name = rdb_xid_to_string(*xid);
4880
4881 rocksdb::Transaction *const trx = rdb->GetTransactionByName(name);
4882
4883 if (trx == nullptr) {
4884 DBUG_RETURN(XAER_NOTA);
4885 }
4886
4887 const rocksdb::Status s = trx->Rollback();
4888
4889 if (!s.ok()) {
4890 rdb_log_status_error(s);
4891 DBUG_RETURN(XAER_RMERR);
4892 }
4893
4894 delete trx;
4895
4896 DBUG_RETURN(XA_OK);
4897 }
4898
4899 /**
4900 Rebuilds an XID from a serialized version stored in a string.
4901 */
4902 23 static void rdb_xid_from_string(const std::string &src, XID *const dst) {
4903
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 assert(dst != nullptr);
4904 23 uint offset = 0;
4905 uint64 raw_fid8 =
4906 23 rdb_netbuf_to_uint64(reinterpret_cast<const uchar *>(src.data()));
4907 23 const int64 signed_fid8 = *reinterpret_cast<int64 *>(&raw_fid8);
4908
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 dst->set_format_id(signed_fid8);
4909 23 offset += RDB_FORMATID_SZ;
4910
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 dst->set_gtrid_length(src.at(offset));
4911 23 offset += RDB_GTRID_SZ;
4912
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 dst->set_bqual_length(src.at(offset));
4913 23 offset += RDB_BQUAL_SZ;
4914
4915
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 assert(dst->get_gtrid_length() >= 0);
4916
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 assert(dst->get_gtrid_length() <= MAXGTRIDSIZE);
4917
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 assert(dst->get_bqual_length() >= 0);
4918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 assert(dst->get_bqual_length() <= MAXBQUALSIZE);
4919
4920 const std::string &tmp_data = src.substr(
4921
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 RDB_XIDHDR_LEN, (dst->get_gtrid_length()) + (dst->get_bqual_length()));
4922 23 dst->set_data(tmp_data.data(), tmp_data.length());
4923 23 }
4924
4925 902 static int rocksdb_recover(handlerton *hton, XA_recover_txn *txn_list, uint len,
4926 MEM_ROOT *mem_root) {
4927
2/4
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 902 times.
902 if (len == 0 || txn_list == nullptr) {
4928 return HA_EXIT_SUCCESS;
4929 }
4930
4931 902 std::vector<rocksdb::Transaction *> trans_list;
4932
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 rdb->GetAllPreparedTransactions(&trans_list);
4933
4934 902 uint count = 0;
4935
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 902 times.
925 for (auto &trans : trans_list) {
4936
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (count >= len) {
4937 break;
4938 }
4939
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 auto name = trans->GetName();
4940
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 rdb_xid_from_string(name, &(txn_list[count].id));
4941
4942
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
46 txn_list[count].mod_tables = new (mem_root) List<st_handler_tablename>();
4943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (!txn_list[count].mod_tables) break;
4944
4945 23 count++;
4946
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 }
4947 902 return count;
4948 902 }
4949
4950 4004239 static int rocksdb_commit(handlerton *const hton, THD *const thd,
4951 bool commit_tx) {
4952
1/2
✓ Branch 0 taken 4004239 times.
✗ Branch 1 not taken.
4004239 DBUG_ENTER_FUNC();
4953
4954
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4004239 times.
4004239 assert(hton != nullptr);
4955
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4004239 times.
4004239 assert(thd != nullptr);
4956
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4004239 times.
4004239 assert(commit_latency_stats != nullptr);
4957
4958
2/4
✓ Branch 0 taken 4004239 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4004239 times.
✗ Branch 3 not taken.
4004239 auto clock = rocksdb::Env::Default()->GetSystemClock().get();
4959
1/2
✓ Branch 0 taken 4004239 times.
✗ Branch 1 not taken.
4004239 rocksdb::StopWatchNano timer(clock, true);
4960
4961 /* note: h->external_lock(F_UNLCK) is called after this function is called) */
4962
1/2
✓ Branch 0 taken 4004239 times.
✗ Branch 1 not taken.
4004239 Rdb_transaction *tx = get_tx_from_thd(thd);
4963
4964 /* this will trigger saving of perf_context information */
4965
2/4
✓ Branch 0 taken 4004239 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4004239 times.
✗ Branch 3 not taken.
4004239 Rdb_perf_context_guard guard(tx, rocksdb_perf_context_level(thd));
4966
4967
1/2
✓ Branch 0 taken 4004239 times.
✗ Branch 1 not taken.
4004239 if (tx != nullptr) {
4968
7/8
✓ Branch 0 taken 3972222 times.
✓ Branch 1 taken 32017 times.
✓ Branch 2 taken 3972222 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3551518 times.
✓ Branch 5 taken 420704 times.
✓ Branch 6 taken 3583535 times.
✓ Branch 7 taken 420704 times.
4004239 if (commit_tx || (!my_core::thd_test_options(
4969 thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
4970 /*
4971 We get here
4972 - For a COMMIT statement that finishes a multi-statement transaction
4973 - For a statement that has its own transaction
4974 */
4975
3/4
✓ Branch 0 taken 3583535 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3583532 times.
3583535 if (tx->commit()) {
4976
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(HA_ERR_ROCKSDB_COMMIT_FAILED);
4977 }
4978 } else {
4979 /*
4980 We get here when committing a statement within a transaction.
4981 */
4982 420704 tx->set_tx_failed(false);
4983
1/2
✓ Branch 0 taken 420704 times.
✗ Branch 1 not taken.
420704 tx->make_stmt_savepoint_permanent();
4984 }
4985
4986
3/4
✓ Branch 0 taken 4004236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 140486 times.
✓ Branch 3 taken 3863750 times.
4004236 if (my_core::thd_tx_isolation(thd) <= ISO_READ_COMMITTED) {
4987 // For READ_COMMITTED, we release any existing snapshot so that we will
4988 // see any changes that occurred since the last statement.
4989
1/2
✓ Branch 0 taken 140486 times.
✗ Branch 1 not taken.
140486 tx->release_snapshot();
4990 }
4991 }
4992
4993 // `Add()` is implemented in a thread-safe manner.
4994
2/4
✓ Branch 0 taken 4004236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4004236 times.
✗ Branch 3 not taken.
4004236 commit_latency_stats->Add(timer.ElapsedNanos() / 1000);
4995
4996
1/2
✓ Branch 0 taken 4004236 times.
✗ Branch 1 not taken.
4004236 DBUG_RETURN(HA_EXIT_SUCCESS);
4997 4004239 }
4998
4999 4036 static int rocksdb_rollback(handlerton *const hton, THD *const thd,
5000 bool rollback_tx) {
5001
1/2
✓ Branch 0 taken 4036 times.
✗ Branch 1 not taken.
4036 Rdb_transaction *tx = get_tx_from_thd(thd);
5002
2/4
✓ Branch 0 taken 4036 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4036 times.
✗ Branch 3 not taken.
4036 Rdb_perf_context_guard guard(tx, rocksdb_perf_context_level(thd));
5003
5004
1/2
✓ Branch 0 taken 4036 times.
✗ Branch 1 not taken.
4036 if (tx != nullptr) {
5005
2/2
✓ Branch 0 taken 578 times.
✓ Branch 1 taken 3458 times.
4036 if (rollback_tx) {
5006 /*
5007 We get here, when
5008 - ROLLBACK statement is issued.
5009
5010 Discard the changes made by the transaction
5011 */
5012
1/2
✓ Branch 0 taken 578 times.
✗ Branch 1 not taken.
578 tx->rollback();
5013 } else {
5014 /*
5015 We get here when
5016 - a statement with AUTOCOMMIT=1 is being rolled back (because of some
5017 error)
5018 - a statement inside a transaction is rolled back
5019 */
5020
5021
1/2
✓ Branch 0 taken 3458 times.
✗ Branch 1 not taken.
3458 tx->rollback_stmt();
5022 3458 tx->set_tx_failed(true);
5023 }
5024
5025
3/4
✓ Branch 0 taken 4036 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 672 times.
✓ Branch 3 taken 3364 times.
4036 if (my_core::thd_tx_isolation(thd) <= ISO_READ_COMMITTED) {
5026 // For READ_COMMITTED, we release any existing snapshot so that we will
5027 // see any changes that occurred since the last statement.
5028
1/2
✓ Branch 0 taken 672 times.
✗ Branch 1 not taken.
672 tx->release_snapshot();
5029 }
5030 }
5031 4036 return HA_EXIT_SUCCESS;
5032 4036 }
5033
5034 27 static bool print_stats(THD *const thd, std::string const &type,
5035 std::string const &name, std::string const &status,
5036 stat_print_fn *stat_print) {
5037 27 return stat_print(thd, type.c_str(), type.size(), name.c_str(), name.size(),
5038 27 status.c_str(), status.size());
5039 }
5040
5041 48 static std::string format_string(const char *const format, ...) {
5042 48 std::string res;
5043 va_list args;
5044 va_list args_copy;
5045 char static_buff[256];
5046
5047
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 assert(format != nullptr);
5048
5049 48 va_start(args, format);
5050 48 va_copy(args_copy, args);
5051
5052 // Calculate how much space we will need
5053 48 int len = vsnprintf(nullptr, 0, format, args);
5054 48 va_end(args);
5055
5056
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 if (len < 0) {
5057 res = std::string("<format error>");
5058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 } else if (len == 0) {
5059 // Shortcut for an empty string
5060 res = std::string("");
5061 } else {
5062 // For short enough output use a static buffer
5063 48 char *buff = static_buff;
5064 48 std::unique_ptr<char[]> dynamic_buff = nullptr;
5065
5066 48 len++; // Add one for null terminator
5067
5068 // for longer output use an allocated buffer
5069
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 if (static_cast<uint>(len) > sizeof(static_buff)) {
5070 dynamic_buff.reset(new char[len]);
5071 buff = dynamic_buff.get();
5072 }
5073
5074 // Now re-do the vsnprintf with the buffer which is now large enough
5075 48 (void)vsnprintf(buff, len, format, args_copy);
5076
5077 // Convert to a std::string. Note we could have created a std::string
5078 // large enough and then converted the buffer to a 'char*' and created
5079 // the output in place. This would probably work but feels like a hack.
5080 // Since this isn't code that needs to be super-performant we are going
5081 // with this 'safer' method.
5082
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 res = std::string(buff);
5083 48 }
5084
5085 48 va_end(args_copy);
5086
5087 96 return res;
5088 }
5089
5090 class Rdb_snapshot_status : public Rdb_tx_list_walker {
5091 private:
5092 std::string m_data;
5093
5094 39 static std::string current_timestamp(void) {
5095 static const char *const format = "%d-%02d-%02d %02d:%02d:%02d";
5096 time_t currtime;
5097 struct tm currtm;
5098
5099 39 time(&currtime);
5100
5101 39 localtime_r(&currtime, &currtm);
5102
5103 39 return format_string(format, currtm.tm_year + 1900, currtm.tm_mon + 1,
5104 currtm.tm_mday, currtm.tm_hour, currtm.tm_min,
5105
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
78 currtm.tm_sec);
5106 }
5107
5108 39 static std::string get_header(void) {
5109
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
78 return "\n============================================================\n" +
5110 78 current_timestamp() +
5111 " ROCKSDB TRANSACTION MONITOR OUTPUT\n"
5112 "============================================================\n"
5113 "---------\n"
5114 "SNAPSHOTS\n"
5115 "---------\n"
5116
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
78 "LIST OF SNAPSHOTS FOR EACH SESSION:\n";
5117 }
5118
5119 static std::string get_footer(void) {
5120 return "-----------------------------------------\n"
5121 "END OF ROCKSDB TRANSACTION MONITOR OUTPUT\n"
5122 "=========================================\n";
5123 }
5124
5125 72 static Rdb_deadlock_info::Rdb_dl_trx_info get_dl_txn_info(
5126 const rocksdb::DeadlockInfo &txn, const GL_INDEX_ID &gl_index_id) {
5127 72 Rdb_deadlock_info::Rdb_dl_trx_info txn_data;
5128
5129 72 txn_data.trx_id = txn.m_txn_id;
5130
5131
2/4
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
72 txn_data.table_name = ddl_manager.safe_get_table_name(gl_index_id);
5132
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 48 times.
72 if (txn_data.table_name.empty()) {
5133 txn_data.table_name =
5134
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
24 "NOT FOUND; INDEX_ID: " + std::to_string(gl_index_id.index_id);
5135 }
5136
5137
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 const auto &kd = ddl_manager.safe_find(gl_index_id);
5138 txn_data.index_name =
5139
4/6
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
168 (kd) ? kd->get_name()
5140
4/8
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
240 : "NOT FOUND; INDEX_ID: " + std::to_string(gl_index_id.index_id);
5141
5142 std::shared_ptr<rocksdb::ColumnFamilyHandle> cfh =
5143
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 cf_manager.get_cf(txn.m_cf_id);
5144
5145 // Retrieve CF name from CF handle object, and it is safe if the CF is
5146 // removed from cf_manager at this point.
5147 txn_data.cf_name = (cfh)
5148
5/8
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 66 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
150 ? cfh->GetName()
5149
4/8
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 66 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
222 : "NOT FOUND; CF_ID: " + std::to_string(txn.m_cf_id);
5150
5151 txn_data.waiting_key =
5152
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 rdb_hexdump(txn.m_waiting_key.c_str(), txn.m_waiting_key.length());
5153
5154 72 txn_data.exclusive_lock = txn.m_exclusive;
5155
5156 144 return txn_data;
5157 72 }
5158
5159 36 static Rdb_deadlock_info get_dl_path_trx_info(
5160 const rocksdb::DeadlockPath &path_entry) {
5161 36 Rdb_deadlock_info deadlock_info;
5162
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 deadlock_info.path.reserve(path_entry.path.size());
5163
5164
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 36 times.
108 for (const auto &txn : path_entry.path) {
5165 const GL_INDEX_ID gl_index_id = {
5166 72 txn.m_cf_id, rdb_netbuf_to_uint32(reinterpret_cast<const uchar *>(
5167 72 txn.m_waiting_key.c_str()))};
5168
2/4
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
72 deadlock_info.path.push_back(get_dl_txn_info(txn, gl_index_id));
5169 }
5170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 assert_IFF(path_entry.limit_exceeded, path_entry.path.empty());
5171 /* print the first txn in the path to display the full deadlock cycle */
5172
3/6
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
36 if (!path_entry.path.empty() && !path_entry.limit_exceeded) {
5173 36 const auto &deadlocking_txn = *(path_entry.path.end() - 1);
5174 36 deadlock_info.victim_trx_id = deadlocking_txn.m_txn_id;
5175 36 deadlock_info.deadlock_time = path_entry.deadlock_time;
5176 }
5177 36 return deadlock_info;
5178 }
5179
5180 public:
5181
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 Rdb_snapshot_status() : m_data(get_header()) {}
5182
5183 std::string getResult() { return m_data + get_footer(); }
5184
5185 /* Implement Rdb_transaction interface */
5186 /* Create one row in the snapshot status table */
5187 93 void process_tran(const Rdb_transaction *const tx) override {
5188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 93 times.
93 assert(tx != nullptr);
5189
5190 /* Calculate the duration the snapshot has existed */
5191 93 int64_t snapshot_timestamp = tx->m_snapshot_timestamp;
5192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 93 times.
93 if (snapshot_timestamp != 0) {
5193 int64_t curr_time;
5194 rdb->GetEnv()->GetCurrentTime(&curr_time);
5195
5196 THD *thd = tx->get_thd();
5197 char buffer[1024];
5198 thd_security_context(thd, buffer, sizeof buffer, 0);
5199 m_data += format_string(
5200 "---SNAPSHOT, ACTIVE %lld sec\n"
5201 "%s\n"
5202 "lock count %llu, write count %llu\n",
5203 curr_time - snapshot_timestamp, buffer, tx->get_row_lock_count(),
5204 tx->get_write_count());
5205 }
5206 93 }
5207
5208 39 std::vector<Rdb_deadlock_info> get_deadlock_info() {
5209 39 std::vector<Rdb_deadlock_info> deadlock_info;
5210
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 const auto &dlock_buffer = rdb->GetDeadlockInfoBuffer();
5211
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 39 times.
84 for (const auto &path_entry : dlock_buffer) {
5212
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 9 times.
45 if (!path_entry.limit_exceeded) {
5213
2/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
36 deadlock_info.push_back(get_dl_path_trx_info(path_entry));
5214 }
5215 }
5216 78 return deadlock_info;
5217 39 }
5218 };
5219
5220 /**
5221 * @brief
5222 * walks through all non-replication transactions and copies
5223 * out relevant information for information_schema.rocksdb_trx
5224 */
5225 class Rdb_trx_info_aggregator : public Rdb_tx_list_walker {
5226 private:
5227 std::vector<Rdb_trx_info> *m_trx_info;
5228
5229 public:
5230 77 explicit Rdb_trx_info_aggregator(std::vector<Rdb_trx_info> *const trx_info)
5231 77 : m_trx_info(trx_info) {}
5232
5233 246 void process_tran(const Rdb_transaction *const tx) override {
5234 static const std::map<int, std::string> state_map = {
5235 {rocksdb::Transaction::STARTED, "STARTED"},
5236 {rocksdb::Transaction::AWAITING_PREPARE, "AWAITING_PREPARE"},
5237 {rocksdb::Transaction::PREPARED, "PREPARED"},
5238 {rocksdb::Transaction::AWAITING_COMMIT, "AWAITING_COMMIT"},
5239 {rocksdb::Transaction::COMMITED, "COMMITED"},
5240 {rocksdb::Transaction::AWAITING_ROLLBACK, "AWAITING_ROLLBACK"},
5241 {rocksdb::Transaction::ROLLEDBACK, "ROLLEDBACK"},
5242
13/26
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 222 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 24 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 24 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 24 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 24 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 24 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 24 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 24 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 168 times.
✓ Branch 21 taken 24 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
414 };
5243 static const size_t trx_query_max_len = 1024; // length stolen from InnoDB
5244
5245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 246 times.
246 assert(tx != nullptr);
5246
5247 246 THD *const thd = tx->get_thd();
5248 246 const my_thread_id thread_id = thd->thread_id();
5249
5250
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 240 times.
246 if (tx->is_writebatch_trx()) {
5251 6 const auto wb_impl = static_cast<const Rdb_writebatch_impl *>(tx);
5252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 assert(wb_impl);
5253
5/10
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
18 m_trx_info->push_back(
5254 {"", /* name */
5255 0, /* trx_id */
5256 6 wb_impl->get_write_count(), 0, /* lock_count */
5257 0, /* timeout_sec */
5258 "", /* state */
5259 "", /* waiting_key */
5260 0, /* waiting_cf_id */
5261 1, /*is_replication */
5262 1, /* skip_trx_api */
5263 6 wb_impl->is_tx_read_only(), 0, /* deadlock detection */
5264 6 wb_impl->num_ongoing_bulk_load(), thread_id, "" /* query string */});
5265 } else {
5266 240 const auto tx_impl = static_cast<const Rdb_transaction_impl *>(tx);
5267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
240 assert(tx_impl);
5268 240 const rocksdb::Transaction *rdb_trx = tx_impl->get_rdb_trx();
5269
5270
2/2
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 161 times.
240 if (rdb_trx == nullptr) {
5271 79 return;
5272 }
5273
5274 161 std::string query_str;
5275
1/2
✓ Branch 0 taken 161 times.
✗ Branch 1 not taken.
161 query_str.reserve(trx_query_max_len + 1);
5276
2/4
✓ Branch 0 taken 161 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 161 times.
✗ Branch 3 not taken.
161 size_t query_len = thd_query_safe(thd, &query_str[0], trx_query_max_len);
5277
1/2
✓ Branch 0 taken 161 times.
✗ Branch 1 not taken.
161 query_str.resize(query_len);
5278
5279
1/2
✓ Branch 0 taken 161 times.
✗ Branch 1 not taken.
161 const auto state_it = state_map.find(rdb_trx->GetState());
5280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 161 times.
161 assert(state_it != state_map.end());
5281 161 const int is_replication = (thd->rli_slave != nullptr);
5282 uint32_t waiting_cf_id;
5283 161 std::string waiting_key;
5284
1/2
✓ Branch 0 taken 161 times.
✗ Branch 1 not taken.
161 rdb_trx->GetWaitingTxns(&waiting_cf_id, &waiting_key),
5285
5286
2/4
✓ Branch 0 taken 161 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 161 times.
✗ Branch 3 not taken.
322 m_trx_info->push_back(
5287
2/4
✓ Branch 0 taken 161 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 161 times.
✗ Branch 3 not taken.
161 {rdb_trx->GetName(), rdb_trx->GetID(), tx_impl->get_write_count(),
5288 161 tx_impl->get_row_lock_count(), tx_impl->get_timeout_sec(),
5289
1/2
✓ Branch 0 taken 161 times.
✗ Branch 1 not taken.
161 state_it->second, waiting_key, waiting_cf_id, is_replication,
5290 0, /* skip_trx_api */
5291
1/2
✓ Branch 0 taken 161 times.
✗ Branch 1 not taken.
161 tx_impl->is_tx_read_only(), rdb_trx->IsDeadlockDetect(),
5292
1/2
✓ Branch 0 taken 161 times.
✗ Branch 1 not taken.
161 tx_impl->num_ongoing_bulk_load(), thread_id, query_str});
5293 161 }
5294 }
5295 };
5296
5297 /*
5298 returns a vector of info for all non-replication threads
5299 for use by information_schema.rocksdb_trx
5300 */
5301 77 std::vector<Rdb_trx_info> rdb_get_all_trx_info() {
5302 77 std::vector<Rdb_trx_info> trx_info;
5303 77 Rdb_trx_info_aggregator trx_info_agg(&trx_info);
5304
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 Rdb_transaction::walk_tx_list(&trx_info_agg);
5305 154 return trx_info;
5306 77 }
5307
5308 /*
5309 returns a vector of info of recent deadlocks
5310 for use by information_schema.rocksdb_deadlock
5311 */
5312 39 std::vector<Rdb_deadlock_info> rdb_get_deadlock_info() {
5313
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 Rdb_snapshot_status showStatus;
5314
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 Rdb_transaction::walk_tx_list(&showStatus);
5315
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
78 return showStatus.get_deadlock_info();
5316 39 }
5317
5318 /*
5319 This is called for SHOW ENGINE ROCKSDB STATUS | LOGS | etc.
5320
5321 For now, produce info about live files (which gives an imprecise idea about
5322 what column families are there).
5323 */
5324 9 static bool rocksdb_show_status(handlerton *const hton, THD *const thd,
5325 stat_print_fn *const stat_print,
5326 enum ha_stat_type stat_type) {
5327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 assert(hton != nullptr);
5328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 assert(thd != nullptr);
5329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 assert(stat_print != nullptr);
5330
5331 9 bool res = false;
5332 9 char buf[100] = {'\0'};
5333
5334
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if (stat_type == HA_ENGINE_STATUS) {
5335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 assert(rdb != nullptr);
5336
5337 3 std::string str;
5338
5339 /* Global DB Statistics */
5340
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rocksdb_stats) {
5341
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 str = rocksdb_stats->ToString();
5342
5343 // Use the same format as internal RocksDB statistics entries to make
5344 // sure that output will look unified.
5345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 assert(commit_latency_stats != nullptr);
5346
5347 15 snprintf(buf, sizeof(buf),
5348 "rocksdb.commit_latency statistics "
5349 "Percentiles :=> 50 : %.2f 95 : %.2f "
5350 "99 : %.2f 100 : %.2f\n",
5351
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 commit_latency_stats->Percentile(50),
5352
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 commit_latency_stats->Percentile(95),
5353
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 commit_latency_stats->Percentile(99),
5354
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 commit_latency_stats->Percentile(100));
5355
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 str.append(buf);
5356
5357 3 uint64_t v = 0;
5358
5359 // Retrieve additional stalling related numbers from RocksDB and append
5360 // them to the buffer meant for displaying detailed statistics. The intent
5361 // here is to avoid adding another row to the query output because of
5362 // just two numbers.
5363 //
5364 // NB! We're replacing hyphens with underscores in output to better match
5365 // the existing naming convention.
5366
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 if (rdb->GetIntProperty("rocksdb.is-write-stopped", &v)) {
5367 3 snprintf(buf, sizeof(buf),
5368 "rocksdb.is_write_stopped COUNT : %" PRIu64 "\n", v);
5369
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 str.append(buf);
5370 }
5371
5372
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 if (rdb->GetIntProperty("rocksdb.actual-delayed-write-rate", &v)) {
5373 3 snprintf(buf, sizeof(buf),
5374 "rocksdb.actual_delayed_write_rate "
5375 "COUNT : %" PRIu64 "\n",
5376 v);
5377
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 str.append(buf);
5378 }
5379
5380
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 res |= print_stats(thd, "STATISTICS", "rocksdb", str, stat_print);
5381 }
5382
5383 /* Per DB stats */
5384
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 if (rdb->GetProperty("rocksdb.dbstats", &str)) {
5385
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 res |= print_stats(thd, "DBSTATS", "rocksdb", str, stat_print);
5386 }
5387
5388 /* Per column family stats */
5389
3/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 3 times.
15 for (const auto &cf_name : cf_manager.get_cf_names()) {
5390 std::shared_ptr<rocksdb::ColumnFamilyHandle> cfh =
5391
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 cf_manager.get_cf(cf_name);
5392
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!cfh) {
5393 continue;
5394 }
5395
5396 // Retrieve information from CF handle object.
5397 // Even if the CF is removed from CF_manager, the handle object
5398 // is valid.
5399
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
12 if (!rdb->GetProperty(cfh.get(), "rocksdb.cfstats", &str)) {
5400 continue;
5401 }
5402
5403
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 res |= print_stats(thd, "CF_COMPACTION", cf_name, str, stat_print);
5404
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
15 }
5405
5406 /* Memory Statistics */
5407 3 std::vector<rocksdb::DB *> dbs;
5408 3 std::unordered_set<const rocksdb::Cache *> cache_set;
5409 3 size_t internal_cache_count = 0;
5410 3 size_t kDefaultInternalCacheSize = 8 * 1024 * 1024;
5411
5412
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 dbs.push_back(rdb);
5413
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 cache_set.insert(rocksdb_tbl_options->block_cache.get());
5414
5415
3/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 3 times.
15 for (const auto &cf_handle : cf_manager.get_all_cf()) {
5416 // It is safe if the CF handle is removed from cf_manager
5417 // at this point.
5418
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 rocksdb::ColumnFamilyDescriptor cf_desc;
5419
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 cf_handle->GetDescriptor(&cf_desc);
5420 12 auto *const table_factory = cf_desc.options.table_factory.get();
5421
5422
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (table_factory != nullptr) {
5423
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 std::string tf_name = table_factory->Name();
5424
5425
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (tf_name.find("BlockBasedTable") != std::string::npos) {
5426 const auto bbt_opt =
5427
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 table_factory->GetOptions<rocksdb::BlockBasedTableOptions>();
5428
5429
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (bbt_opt != nullptr) {
5430
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (bbt_opt->block_cache.get() != nullptr) {
5431
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 cache_set.insert(bbt_opt->block_cache.get());
5432 } else {
5433 internal_cache_count++;
5434 }
5435
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 cache_set.insert(bbt_opt->block_cache_compressed.get());
5436 }
5437 }
5438 12 }
5439 15 }
5440
5441 3 std::map<rocksdb::MemoryUtil::UsageType, uint64_t> temp_usage_by_type;
5442 3 str.clear();
5443
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 rocksdb::MemoryUtil::GetApproximateMemoryUsageByType(dbs, cache_set,
5444 &temp_usage_by_type);
5445
5446 3 snprintf(buf, sizeof(buf), "\nMemTable Total: %" PRIu64,
5447
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 temp_usage_by_type[rocksdb::MemoryUtil::kMemTableTotal]);
5448
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 str.append(buf);
5449 3 snprintf(buf, sizeof(buf), "\nMemTable Unflushed: %" PRIu64,
5450
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 temp_usage_by_type[rocksdb::MemoryUtil::kMemTableUnFlushed]);
5451
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 str.append(buf);
5452 3 snprintf(buf, sizeof(buf), "\nTable Readers Total: %" PRIu64,
5453
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 temp_usage_by_type[rocksdb::MemoryUtil::kTableReadersTotal]);
5454
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 str.append(buf);
5455 3 snprintf(buf, sizeof(buf), "\nCache Total: %" PRIu64,
5456
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 temp_usage_by_type[rocksdb::MemoryUtil::kCacheTotal]);
5457
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 str.append(buf);
5458 3 snprintf(buf, sizeof(buf), "\nDefault Cache Capacity: %" PRIu64,
5459 internal_cache_count *
5460 static_cast<uint64_t>(kDefaultInternalCacheSize));
5461
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 str.append(buf);
5462
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 res |= print_stats(thd, "MEMORY_STATS", "rocksdb", str, stat_print);
5463
5464 /* Show the background thread status */
5465 3 std::vector<rocksdb::ThreadStatus> thread_list;
5466
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 rocksdb::Status s = rdb->GetEnv()->GetThreadList(&thread_list);
5467
5468 // GetThreadList() may return Status::NotSupported when
5469 // ROCKSDB_USING_THREAD_STATUS is not defined
5470
3/10
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
3 if (!s.ok() && !s.IsNotSupported()) {
5471 LogPluginErrMsg(ERROR_LEVEL, 0,
5472 "Returned error (%s) from GetThreadList.\n",
5473 s.ToString().c_str());
5474 res |= true;
5475 } else {
5476 /* For each background thread retrieved, print out its information */
5477
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 for (auto &it : thread_list) {
5478 /* Only look at background threads. Ignore user threads, if any. */
5479
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (it.thread_type > rocksdb::ThreadStatus::LOW_PRIORITY) {
5480 continue;
5481 }
5482
5483
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
12 str = "\nthread_type: " + it.GetThreadTypeName(it.thread_type) +
5484
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
12 "\ncf_name: " + it.cf_name +
5485
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
18 "\noperation_type: " + it.GetOperationName(it.operation_type) +
5486
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 "\noperation_stage: " +
5487
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
18 it.GetOperationStageName(it.operation_stage) +
5488
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
18 "\nelapsed_time_ms: " + it.MicrosToString(it.op_elapsed_micros);
5489
5490 6 for (auto &it_props : it.InterpretOperationProperties(
5491
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
12 it.operation_type, it.op_properties)) {
5492 str += "\n" + it_props.first + ": " + std::to_string(it_props.second);
5493 6 }
5494
5495
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 str += "\nstate_type: " + it.GetStateName(it.state_type);
5496
5497
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 res |= print_stats(thd, "BG_THREADS", std::to_string(it.thread_id), str,
5498 stat_print);
5499 }
5500 }
5501 3 }
5502
5503
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (res) {
5504 my_error(ER_UNKNOWN_ERROR, MYF(0), "SHOW ENGINE");
5505 }
5506 9 return res;
5507 }
5508
5509 /*
5510 Implements Log_resource lock.
5511
5512 returns false on success
5513 */
5514 6 static bool rocksdb_lock_hton_log(handlerton *const /* unused */) {
5515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 assert(rdb != nullptr);
5516
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 return !rdb->LockWAL().ok();
5517 }
5518
5519 /*
5520 Implements Log_resource unlock.
5521
5522 returns false on success
5523 */
5524 6 static bool rocksdb_unlock_hton_log(handlerton *const /* unused */) {
5525
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 assert(rdb != nullptr);
5526
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 return !rdb->UnlockWAL().ok();
5527 }
5528
5529 /*
5530 Implements Log_resource collect_info.
5531
5532 Produces JSON object with following structure:
5533
5534 "RocksDB": {
5535 "wal_files": [
5536 { "log_number": N, "path_name": "...", "file_size_bytes": K },
5537 ...
5538 ]
5539 }
5540
5541 returns JSON dom to receive the log info
5542 */
5543 6 static bool rocksdb_collect_hton_log_info(handlerton *const /* unused */,
5544 Json_dom *json) {
5545 6 bool ret_val = false;
5546 6 rocksdb::VectorLogPtr live_wal_files;
5547
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 const auto s = rdb->GetSortedWalFiles(live_wal_files);
5548
5549
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (!s.ok()) {
5550 return true;
5551 }
5552
5553 6 Json_object *json_engines = static_cast<Json_object *>(json);
5554
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 Json_object json_rocksdb;
5555
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 Json_array json_wal_files;
5556
5557 6 size_t index = 0;
5558
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 6 times.
124 for (const auto &wal : live_wal_files) {
5559
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 Json_uint json_log_number(wal->LogNumber());
5560
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 Json_string json_path_name(wal->PathName());
5561
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 Json_uint json_size_file_bytes(wal->SizeFileBytes());
5562
5563
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 Json_object json_wal;
5564
2/4
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
118 ret_val = json_wal.add_clone("log_number", &json_log_number);
5565
3/6
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 118 times.
✗ Branch 5 not taken.
118 if (!ret_val) json_wal.add_clone("path_name", &json_path_name);
5566
3/6
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 118 times.
✗ Branch 5 not taken.
118 if (!ret_val) json_wal.add_clone("size_file_bytes", &json_size_file_bytes);
5567
2/4
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
118 if (!ret_val) json_wal_files.insert_clone(index, &json_wal);
5568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 if (ret_val) break;
5569 118 ++index;
5570
4/8
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 118 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 118 times.
✗ Branch 7 not taken.
118 }
5571
5572
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 if (!ret_val) ret_val = json_rocksdb.add_clone("wal_files", &json_wal_files);
5573
5574
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 if (!ret_val) ret_val = json_engines->add_clone("RocksDB", &json_rocksdb);
5575
5576 6 return ret_val;
5577 6 }
5578
5579 3983747 static inline void rocksdb_register_tx(handlerton *const hton, THD *const thd,
5580 Rdb_transaction *const tx) {
5581
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3983747 times.
3983747 assert(tx != nullptr);
5582
5583 3983747 trans_register_ha(thd, false, rocksdb_hton, nullptr);
5584
2/2
✓ Branch 0 taken 1303204 times.
✓ Branch 1 taken 2680945 times.
3984149 if (rocksdb_write_policy == rocksdb::TxnDBWritePolicy::WRITE_UNPREPARED) {
5585 // Some internal operations will call trans_register_ha, but they do not
5586 // go through 2pc. In this case, the xid is set with query_id == 0, which
5587 // means that rocksdb will receive transactions with duplicate names.
5588 //
5589 // Skip setting name in these cases.
5590
1/2
✓ Branch 0 taken 1303215 times.
✗ Branch 1 not taken.
1303204 if (thd->query_id != 0) {
5591 1303215 tx->set_name();
5592 }
5593 }
5594
2/2
✓ Branch 0 taken 423926 times.
✓ Branch 1 taken 3560247 times.
3984185 if (my_core::thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
5595 423926 tx->start_stmt();
5596 423926 trans_register_ha(thd, true, rocksdb_hton, nullptr);
5597 }
5598 3984173 }
5599
5600 /*
5601 Supporting START TRANSACTION WITH CONSISTENT SNAPSHOT
5602
5603 - START TRANSACTION WITH CONSISTENT SNAPSHOT
5604 takes both InnoDB and RocksDB snapshots, and both InnoDB and RocksDB
5605 participate in transaction. When executing COMMIT, both InnoDB and
5606 RocksDB modifications are committed. Remember that XA is not supported yet,
5607 so mixing engines is not recommended anyway.
5608 */
5609 56 static int rocksdb_start_tx_and_assign_read_view(
5610 handlerton *const hton, /*!< in: RocksDB handlerton */
5611 THD *const thd) /*!< in: MySQL thread handle of the
5612 user for whom the transaction should
5613 be committed */
5614 {
5615
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 ulong const tx_isolation = my_core::thd_tx_isolation(thd);
5616
5617
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 Rdb_transaction *tx = get_or_create_tx(thd);
5618
2/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
56 Rdb_perf_context_guard guard(tx, rocksdb_perf_context_level(thd));
5619
5620
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 assert(!tx->has_snapshot());
5621 56 tx->set_tx_read_only(true);
5622
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 rocksdb_register_tx(hton, thd, tx);
5623
5624
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 if (tx_isolation == ISO_REPEATABLE_READ) {
5625
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 tx->acquire_snapshot(true);
5626 } else {
5627 push_warning_printf(thd, Sql_condition::SL_WARNING, HA_ERR_UNSUPPORTED,
5628 "RocksDB: Only REPEATABLE READ isolation level is "
5629 "supported for START TRANSACTION WITH CONSISTENT "
5630 "SNAPSHOT in RocksDB Storage Engine. Snapshot has not "
5631 "been taken.");
5632 }
5633 56 return HA_EXIT_SUCCESS;
5634 56 }
5635
5636 /* Dummy SAVEPOINT support. This is needed for long running transactions
5637 * like mysqldump (https://bugs.mysql.com/bug.php?id=71017).
5638 * Current SAVEPOINT does not correctly handle ROLLBACK and does not return
5639 * errors. This needs to be addressed in future versions (Issue#96).
5640 */
5641 60 static int rocksdb_savepoint(handlerton *const hton, THD *const thd,
5642 void *const savepoint) {
5643 60 return HA_EXIT_SUCCESS;
5644 }
5645
5646 45 static int rocksdb_rollback_to_savepoint(handlerton *const hton, THD *const thd,
5647 void *const savepoint) {
5648 45 Rdb_transaction *tx = get_tx_from_thd(thd);
5649 45 return tx->rollback_to_savepoint(savepoint);
5650 }
5651
5652 18 static bool rocksdb_rollback_to_savepoint_can_release_mdl(
5653 handlerton *const hton, THD *const thd) {
5654 18 return true;
5655 }
5656
5657 463288 static void rocksdb_get_stats(ha_statistics *stats, Rdb_tbl_def *tbl_def) {
5658 463288 stats->records = 0;
5659 463288 stats->index_file_length = 0ul;
5660 463288 stats->data_file_length = 0ul;
5661 463288 stats->mean_rec_length = 0;
5662
5663
2/2
✓ Branch 0 taken 757322 times.
✓ Branch 1 taken 463289 times.
1220611 for (uint i = 0; i < tbl_def->m_key_count; i++) {
5664 757322 auto key_def = tbl_def->m_key_descr_arr[i];
5665
2/2
✓ Branch 0 taken 463288 times.
✓ Branch 1 taken 294034 times.
757324 if (key_def->is_primary_key()) {
5666 463288 stats->data_file_length = key_def->m_stats.m_actual_disk_size;
5667 463288 stats->records = key_def->m_stats.m_rows;
5668 } else {
5669 294034 stats->index_file_length += key_def->m_stats.m_actual_disk_size;
5670 }
5671 757320 }
5672 463289 }
5673
5674 /*
5675 This is called for INFORMATION_SCHEMA.TABLES
5676 */
5677 402 static bool rocksdb_get_table_statistics(
5678 const char *db_name, const char *table_name,
5679 dd::Object_id /*se_private_id*/,
5680 const dd::Properties & /*ts_se_private_data*/,
5681 const dd::Properties & /*tbl_se_private_data*/, uint /*stat_flags*/,
5682 ha_statistics *stats) {
5683
1/2
✓ Branch 0 taken 402 times.
✗ Branch 1 not taken.
402 std::string fullname = db_name;
5684
1/2
✓ Branch 0 taken 402 times.
✗ Branch 1 not taken.
402 fullname.append(".");
5685
1/2
✓ Branch 0 taken 402 times.
✗ Branch 1 not taken.
402 fullname.append(table_name);
5686
5687 // We are called from within metadata lock MDL_EXPLICIT, so it should be
5688 // safe to access Rdb_tbl_def here
5689
1/2
✓ Branch 0 taken 402 times.
✗ Branch 1 not taken.
402 auto tbl_def = ddl_manager.find(fullname);
5690
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 396 times.
402 if (!tbl_def) {
5691 // Table is missing due to a possible race condition
5692
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 my_error(HA_ERR_NO_SUCH_TABLE, MYF(0), "Table is missing");
5693 6 return true;
5694 }
5695
5696
1/2
✓ Branch 0 taken 396 times.
✗ Branch 1 not taken.
396 int ret = ha_rocksdb::update_stats(stats, tbl_def);
5697
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 396 times.
396 if (ret != HA_EXIT_SUCCESS) {
5698 my_error(ret, MYF(0), "Failed to update table stats");
5699 return true;
5700 }
5701
5702 396 return false;
5703 402 }
5704
5705 920 static rocksdb::Status check_rocksdb_options_compatibility(
5706 const char *const dbpath, const rocksdb::Options &main_opts,
5707 const std::vector<rocksdb::ColumnFamilyDescriptor> &cf_descr) {
5708
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 920 times.
920 assert(rocksdb_datadir != nullptr);
5709
5710
1/2
✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
920 rocksdb::DBOptions loaded_db_opt;
5711 920 std::vector<rocksdb::ColumnFamilyDescriptor> loaded_cf_descs;
5712 rocksdb::Status status =
5713 920 LoadLatestOptions(dbpath, main_opts.env, &loaded_db_opt, &loaded_cf_descs,
5714
2/4
✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 920 times.
✗ Branch 3 not taken.
1840 rocksdb_ignore_unknown_options);
5715
5716 // If we're starting from scratch and there are no options saved yet then this
5717 // is a valid case. Therefore we can't compare the current set of options to
5718 // anything.
5719
3/4
✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 403 times.
✓ Branch 3 taken 517 times.
920 if (status.IsNotFound()) {
5720 403 return rocksdb::Status::OK();
5721 }
5722
5723
3/4
✓ Branch 0 taken 517 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 514 times.
517 if (!status.ok()) {
5724 3 return status;
5725 }
5726
5727
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 514 times.
514 if (loaded_cf_descs.size() != cf_descr.size()) {
5728 return rocksdb::Status::NotSupported(
5729 "Mismatched size of column family "
5730 "descriptors.");
5731 }
5732
5733 // Please see RocksDB documentation for more context about why we need to set
5734 // user-defined functions and pointer-typed options manually.
5735
2/2
✓ Branch 0 taken 2291 times.
✓ Branch 1 taken 514 times.
2805 for (size_t i = 0; i < loaded_cf_descs.size(); i++) {
5736 4582 loaded_cf_descs[i].options.compaction_filter =
5737 2291 cf_descr[i].options.compaction_filter;
5738 2291 loaded_cf_descs[i].options.compaction_filter_factory =
5739 2291 cf_descr[i].options.compaction_filter_factory;
5740 2291 loaded_cf_descs[i].options.comparator = cf_descr[i].options.comparator;
5741 2291 loaded_cf_descs[i].options.memtable_factory =
5742 2291 cf_descr[i].options.memtable_factory;
5743 2291 loaded_cf_descs[i].options.merge_operator =
5744 2291 cf_descr[i].options.merge_operator;
5745 2291 loaded_cf_descs[i].options.prefix_extractor =
5746 2291 cf_descr[i].options.prefix_extractor;
5747 2291 loaded_cf_descs[i].options.table_factory =
5748 2291 cf_descr[i].options.table_factory;
5749 }
5750
5751 // This is the essence of the function - determine if it's safe to open the
5752 // database or not.
5753
2/4
✓ Branch 0 taken 514 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 514 times.
✗ Branch 3 not taken.
1028 status = CheckOptionsCompatibility(dbpath, main_opts.env, main_opts,
5754 loaded_cf_descs,
5755 514 rocksdb_ignore_unknown_options);
5756
5757 514 return status;
5758 920 }
5759
5760 45358 static uint rocksdb_partition_flags() { return (HA_CANNOT_PARTITION_FK); }
5761
5762 1058 bool rdb_has_wsenv() {
5763 #if FB_HAVE_WSENV
5764 return rocksdb_wsenv_path != nullptr && *rocksdb_wsenv_path;
5765 #else
5766 1058 return false;
5767 #endif
5768 }
5769
5770 7006222 bool rdb_sync_wal_supported() {
5771 #if FB_HAVE_WSENV
5772 // wsenv doesn't support SyncWAL=true yet
5773 return !rdb_has_wsenv();
5774 #else
5775 7006222 return true;
5776 #endif
5777 }
5778
5779 /* Clean up tables leftover from truncation */
5780 902 void rocksdb_truncation_table_cleanup(void) {
5781 /* Scan for tables that have the truncation prefix */
5782 struct Rdb_truncate_tbls : public Rdb_tables_scanner {
5783 public:
5784 std::vector<Rdb_tbl_def *> m_tbl_list;
5785 947 int add_table(Rdb_tbl_def *tdef) override {
5786
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 947 times.
947 assert(tdef != nullptr);
5787
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 944 times.
947 if (tdef->base_tablename().find(TRUNCATE_TABLE_PREFIX) !=
5788 std::string::npos) {
5789 3 m_tbl_list.push_back(tdef);
5790 }
5791 947 return HA_EXIT_SUCCESS;
5792 }
5793 902 } collector;
5794
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 ddl_manager.scan_for_tables(&collector);
5795
5796 /*
5797 For now, delete any table found. It's possible to rename them back,
5798 but there's a risk the rename can potentially lead to other inconsistencies.
5799 Removing the old table (which is being truncated anyway) seems to be the
5800 safest solution.
5801 */
5802
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 ha_rocksdb table(rocksdb_hton, nullptr);
5803
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 902 times.
905 for (Rdb_tbl_def *tbl_def : collector.m_tbl_list) {
5804
9/18
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LogPluginErrMsg(WARNING_LEVEL, 0, "Removing truncated leftover table %s",
5805 tbl_def->full_tablename().c_str());
5806
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 table.delete_table(tbl_def);
5807 }
5808 902 }
5809
5810 /*
5811 Storage Engine initialization function, invoked when plugin is loaded.
5812 */
5813
5814 935 static int rocksdb_init_internal(void *const p) {
5815
1/2
✓ Branch 0 taken 935 times.
✗ Branch 1 not taken.
935 DBUG_ENTER_FUNC();
5816
5817 // Validate the assumption about the size of ROCKSDB_SIZEOF_HIDDEN_PK_COLUMN.
5818 static_assert(sizeof(longlong) == 8, "Assuming that longlong is 8 bytes.");
5819
5820 // Lock the handlertons initialized status flag for writing
5821
2/4
✓ Branch 0 taken 935 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 935 times.
✗ Branch 3 not taken.
935 Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(), true);
5822
2/6
✓ Branch 0 taken 935 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 935 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
935 SHIP_ASSERT(!rdb_get_hton_init_state()->initialized());
5823
5824 // Initialize error logging service.
5825
2/4
✓ Branch 0 taken 935 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 935 times.
935 if (init_logging_service_for_plugin(&reg_srv, &log_bi, &log_bs)) {
5826 DBUG_RETURN(HA_EXIT_FAILURE);
5827 }
5828
5829
5/6
✓ Branch 0 taken 935 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 931 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 932 times.
939 if (THDVAR(nullptr, write_disable_wal) &&
5830
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 rocksdb_flush_log_at_trx_commit == FLUSH_LOG_SYNC) {
5831
9/18
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LogPluginErrMsg(ERROR_LEVEL, 0,
5832 "Invalid argument: Sync writes "
5833 "(rocksdb_flush_log_at_trx_commit == 1) has to enable WAL");
5834
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(1);
5835 }
5836
5837 #ifdef FB_HAVE_WSENV
5838 // Initialize WSEnv with rocksdb_ws_env_path
5839 if (rdb_has_wsenv()) {
5840 LogPluginErrMsg(
5841 INFORMATION_LEVEL, 0,
5842 "RocksDB: Initializing WSEnvironment: rocksdb_wsenv_path = %s",
5843 rocksdb_wsenv_path);
5844
5845 RegisterCustomObjectsSimple();
5846 rocksdb::Env *ws_env = nullptr;
5847 auto s = rocksdb::Env::LoadEnv(rocksdb_wsenv_path, &ws_env);
5848 if (s.ok()) {
5849 rocksdb_db_options->env = ws_env;
5850 } else {
5851 rdb_log_status_error(s, "Can't initialize WSEnvironment");
5852 DBUG_RETURN(HA_EXIT_FAILURE);
5853 }
5854 }
5855 #else
5856
2/4
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 932 times.
932 if (rocksdb_wsenv_path != nullptr && *rocksdb_wsenv_path) {
5857 // We've turned on WSEnv in the wrong build
5858 LogPluginErrMsg(ERROR_LEVEL, 0, "WSEnvironment not supported. ");
5859 DBUG_RETURN(HA_EXIT_FAILURE);
5860 }
5861 #endif
5862
5863
2/4
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 932 times.
932 if (rdb_has_rocksdb_corruption()) {
5864 LogPluginErrMsg(ERROR_LEVEL, 0,
5865 "There was corruption detected in the RockDB data files. "
5866 "Check error log emitted earlier for more details.");
5867 if (rocksdb_allow_to_start_after_corruption) {
5868 LogPluginErrMsg(INFORMATION_LEVEL, 0,
5869 "Set rocksdb_allow_to_start_after_corruption=0 to "
5870 "prevent server from starting when RocksDB data "
5871 "corruption is detected.");
5872 } else {
5873 LogPluginErrMsg(ERROR_LEVEL, 0,
5874 "The server will exit normally and stop restart "
5875 "attempts. Remove %s file from data directory and start "
5876 "mysqld manually.",
5877 rdb_corruption_marker_file_name().c_str());
5878 exit(0);
5879 }
5880 }
5881
5882 932 rocksdb::Status s;
5883
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 932 times.
932 if (rocksdb_fs_uri) {
5884 std::shared_ptr<rocksdb::FileSystem> fs;
5885 s = rocksdb::FileSystem::Load(rocksdb_fs_uri, &fs);
5886 if (fs == nullptr) {
5887 LogPluginErrMsg(ERROR_LEVEL, 0, "Loading custom file system failed: %s\n",
5888 s.ToString().c_str());
5889 DBUG_RETURN(HA_EXIT_FAILURE);
5890 }
5891 rocksdb_db_options->env = GetCompositeEnv(fs);
5892 }
5893
5894
2/6
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 932 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
932 DBUG_EXECUTE_IF("rocksdb_init_failure_files_corruption",
5895 { DBUG_RETURN(HA_EXIT_FAILURE); });
5896
5897
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 926 times.
932 if (opt_rocksdb_fault_injection_options != nullptr &&
5898
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 *opt_rocksdb_fault_injection_options != '\0') {
5899 3 bool retryable = false;
5900 3 uint32_t failure_ratio = 0;
5901 3 std::vector<rocksdb::FileType> types;
5902
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (parse_fault_injection_params(&retryable, &failure_ratio, &types)) {
5903 DBUG_RETURN(HA_EXIT_FAILURE);
5904 }
5905
5906 auto fs = std::make_shared<rocksdb::FaultInjectionTestFS>(
5907
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 rocksdb_db_options->env->GetFileSystem());
5908
5909
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 rocksdb::IOStatus error_msg = rocksdb::IOStatus::IOError("IO Error");
5910 3 error_msg.SetRetryable(retryable);
5911
5912 3 uint32_t seed = rand();
5913
9/18
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LogPluginErrMsg(INFORMATION_LEVEL, 0,
5914 "Initializing fault injection with params (retry=%d, "
5915 "failure_ratio=%d, seed=%d)",
5916 retryable, failure_ratio, seed);
5917
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 fs->SetRandomWriteError(seed, failure_ratio, error_msg,
5918 /* inject_for_all_file_types */ false, types);
5919
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 fs->EnableWriteErrorInjection();
5920
5921 static auto fault_env_guard =
5922 6 std::make_shared<rocksdb::CompositeEnvWrapper>(rocksdb_db_options->env,
5923
3/8
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 fs);
5924 3 rocksdb_db_options->env = fault_env_guard.get();
5925
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 }
5926
5927 // Validate the assumption about the size of ROCKSDB_SIZEOF_HIDDEN_PK_COLUMN.
5928 static_assert(sizeof(longlong) == 8, "Assuming that longlong is 8 bytes.");
5929
5930
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 init_rocksdb_psi_keys();
5931
5932 932 rocksdb_hton = (handlerton *)p;
5933
5934
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 rdb_open_tables.init();
5935
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
962 Ensure_cleanup rdb_open_tables_cleanup([]() { rdb_open_tables.free(); });
5936
5937 #ifdef HAVE_PSI_INTERFACE
5938
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 rdb_bg_thread.init(rdb_signal_bg_psi_mutex_key, rdb_signal_bg_psi_cond_key);
5939
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 rdb_drop_idx_thread.init(rdb_signal_drop_idx_psi_mutex_key,
5940 rdb_signal_drop_idx_psi_cond_key);
5941
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 rdb_is_thread.init(rdb_signal_is_psi_mutex_key, rdb_signal_is_psi_cond_key);
5942
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 rdb_mc_thread.init(rdb_signal_mc_psi_mutex_key, rdb_signal_mc_psi_cond_key);
5943 #else
5944 rdb_bg_thread.init();
5945 rdb_drop_idx_thread.init();
5946 rdb_is_thread.init();
5947 rdb_mc_thread.init();
5948 #endif
5949
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 rdb_collation_data_mutex.init(rdb_collation_data_mutex_key,
5950 MY_MUTEX_INIT_FAST);
5951
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 rdb_mem_cmp_space_mutex.init(rdb_mem_cmp_space_mutex_key, MY_MUTEX_INIT_FAST);
5952
5953 #if defined(HAVE_PSI_INTERFACE)
5954 932 rdb_collation_exceptions =
5955
2/4
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 932 times.
✗ Branch 3 not taken.
932 new Regex_list_handler(key_rwlock_collation_exception_list);
5956 #else
5957 rdb_collation_exceptions = new Regex_list_handler();
5958 #endif
5959
5960
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 rdb_sysvars_mutex.init(rdb_sysvars_psi_mutex_key, MY_MUTEX_INIT_FAST);
5961
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 rdb_block_cache_resize_mutex.init(rdb_block_cache_resize_mutex_key,
5962 MY_MUTEX_INIT_FAST);
5963
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 rdb_bottom_pri_background_compactions_resize_mutex.init(
5964 rdb_bottom_pri_background_compactions_resize_mutex_key,
5965 MY_MUTEX_INIT_FAST);
5966
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 Rdb_transaction::init_mutex();
5967
5968
2/6
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 932 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
932 DBUG_EXECUTE_IF("rocksdb_init_failure_mutexes_initialized", {
5969 DBUG_RETURN(HA_EXIT_FAILURE);
5970 });
5971
5972 932 rocksdb_hton->state = SHOW_OPTION_YES;
5973 932 rocksdb_hton->create = rocksdb_create_handler;
5974 932 rocksdb_hton->close_connection = rocksdb_close_connection;
5975 932 rocksdb_hton->prepare = rocksdb_prepare;
5976 932 rocksdb_hton->commit_by_xid = rocksdb_commit_by_xid;
5977 932 rocksdb_hton->rollback_by_xid = rocksdb_rollback_by_xid;
5978 932 rocksdb_hton->recover = rocksdb_recover;
5979 932 rocksdb_hton->commit = rocksdb_commit;
5980 932 rocksdb_hton->rollback = rocksdb_rollback;
5981 932 rocksdb_hton->db_type = DB_TYPE_ROCKSDB;
5982 932 rocksdb_hton->show_status = rocksdb_show_status;
5983 932 rocksdb_hton->lock_hton_log = rocksdb_lock_hton_log;
5984 932 rocksdb_hton->unlock_hton_log = rocksdb_unlock_hton_log;
5985 932 rocksdb_hton->collect_hton_log_info = rocksdb_collect_hton_log_info;
5986 932 rocksdb_hton->start_consistent_snapshot =
5987 rocksdb_start_tx_and_assign_read_view;
5988 932 rocksdb_hton->savepoint_set = rocksdb_savepoint;
5989 932 rocksdb_hton->savepoint_rollback = rocksdb_rollback_to_savepoint;
5990 932 rocksdb_hton->savepoint_rollback_can_release_mdl =
5991 rocksdb_rollback_to_savepoint_can_release_mdl;
5992 932 rocksdb_hton->get_table_statistics = rocksdb_get_table_statistics;
5993 932 rocksdb_hton->flush_logs = rocksdb_flush_wal;
5994
5995 932 rocksdb_hton->flags = HTON_SUPPORTS_EXTENDED_KEYS | HTON_CAN_RECREATE |
5996 HTON_SUPPORTS_ONLINE_BACKUPS;
5997
5998 932 rocksdb_hton->partition_flags = rocksdb_partition_flags;
5999
6000
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 929 times.
932 if (rocksdb_db_options->max_open_files > (long)open_files_limit) {
6001
9/18
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LogPluginErrMsg(INFORMATION_LEVEL, 0,
6002 "rocksdb_max_open_files should not be greater than the "
6003 "open_files_limit, effective value of "
6004 "rocksdb_max_open_files is being set to open_files_limit / "
6005 "2.");
6006 3 rocksdb_db_options->max_open_files = open_files_limit / 2;
6007
2/2
✓ Branch 0 taken 920 times.
✓ Branch 1 taken 9 times.
929 } else if (rocksdb_db_options->max_open_files == -2) {
6008 920 rocksdb_db_options->max_open_files = open_files_limit / 2;
6009 }
6010
6011
2/4
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 932 times.
✗ Branch 3 not taken.
932 rdb_read_free_regex_handler.set_patterns(DEFAULT_READ_FREE_RPL_TABLES,
6012 get_regex_flags());
6013
6014
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 rocksdb_stats = rocksdb::CreateDBStatistics();
6015 932 rocksdb_stats->set_stats_level(
6016 932 static_cast<rocksdb::StatsLevel>(rocksdb_stats_level));
6017 932 rocksdb_stats_level = rocksdb_stats->get_stats_level();
6018 932 rocksdb_db_options->statistics = rocksdb_stats;
6019
6020
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 928 times.
932 if (rocksdb_rate_limiter_bytes_per_sec != 0) {
6021
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 rocksdb_rate_limiter.reset(
6022 rocksdb::NewGenericRateLimiter(rocksdb_rate_limiter_bytes_per_sec));
6023 4 rocksdb_db_options->rate_limiter = rocksdb_rate_limiter;
6024 }
6025
6026 932 rocksdb_db_options->delayed_write_rate = rocksdb_delayed_write_rate;
6027
6028
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 std::shared_ptr<Rdb_logger> myrocks_logger = std::make_shared<Rdb_logger>();
6029
2/4
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 932 times.
✗ Branch 3 not taken.
1864 s = rocksdb::CreateLoggerFromOptions(rocksdb_datadir, *rocksdb_db_options,
6030 1864 &rocksdb_db_options->info_log);
6031
2/4
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 932 times.
✗ Branch 3 not taken.
932 if (s.ok()) {
6032 932 myrocks_logger->SetRocksDBLogger(rocksdb_db_options->info_log);
6033 }
6034
6035 932 rocksdb_db_options->info_log = myrocks_logger;
6036 932 myrocks_logger->SetInfoLogLevel(
6037
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 static_cast<rocksdb::InfoLogLevel>(rocksdb_info_log_level));
6038
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 rocksdb_db_options->wal_dir = rocksdb_wal_dir;
6039
6040 1864 rocksdb_db_options->wal_recovery_mode =
6041 932 static_cast<rocksdb::WALRecoveryMode>(rocksdb_wal_recovery_mode);
6042
6043 932 rocksdb_db_options->track_and_verify_wals_in_manifest =
6044 rocksdb_track_and_verify_wals_in_manifest;
6045
6046 932 rocksdb_db_options->access_hint_on_compaction_start =
6047 static_cast<rocksdb::Options::AccessHint>(
6048 rocksdb_access_hint_on_compaction_start);
6049
6050
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 929 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 929 times.
935 if (rocksdb_db_options->allow_mmap_reads &&
6051
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 rocksdb_db_options->use_direct_reads) {
6052 // allow_mmap_reads implies !use_direct_reads and RocksDB will not open if
6053 // mmap_reads and direct_reads are both on. (NO_LINT_DEBUG)
6054
9/18
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LogPluginErrMsg(
6055 ERROR_LEVEL, 0,
6056 "Can't enable both use_direct_reads and allow_mmap_reads\n");
6057
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(HA_EXIT_FAILURE);
6058 }
6059
6060 // Check whether the filesystem backing rocksdb_datadir allows O_DIRECT
6061
4/4
✓ Branch 0 taken 926 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 920 times.
1855 if (rocksdb_db_options->use_direct_reads ||
6062
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 920 times.
926 rocksdb_db_options->use_direct_io_for_flush_and_compaction) {
6063
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 rocksdb::EnvOptions soptions;
6064 9 rocksdb::Status check_status;
6065 9 rocksdb::Env *const env = rocksdb_db_options->env;
6066
6067
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 std::string fname = format_string("%s/DIRECT_CHECK", rocksdb_datadir);
6068
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
9 if (env->FileExists(fname).ok()) {
6069 std::unique_ptr<rocksdb::SequentialFile> file;
6070 soptions.use_direct_reads = true;
6071 check_status = env->NewSequentialFile(fname, &file, soptions);
6072 } else {
6073 {
6074 9 std::unique_ptr<rocksdb::WritableFile> file;
6075 9 soptions.use_direct_writes = true;
6076
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 check_status = env->NewWritableFile(fname, &file, soptions);
6077 9 }
6078
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 env->DeleteFile(fname);
6079 }
6080
6081
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if (!check_status.ok()) {
6082 LogPluginErrMsg(ERROR_LEVEL, 0,
6083 "Unable to use direct io in rocksdb-datadir: (%s)",
6084 check_status.ToString().c_str());
6085 DBUG_RETURN(HA_EXIT_FAILURE);
6086 }
6087
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 }
6088
6089
2/6
✓ Branch 0 taken 929 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 929 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
929 DBUG_EXECUTE_IF("rocksdb_init_failure_reads", {
6090 DBUG_RETURN(HA_EXIT_FAILURE);
6091 });
6092
6093
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 926 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 926 times.
932 if (rocksdb_db_options->allow_mmap_writes &&
6094
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 rocksdb_db_options->use_direct_io_for_flush_and_compaction) {
6095 // See above comment for allow_mmap_reads. (NO_LINT_DEBUG)
6096
9/18
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LogPluginErrMsg(ERROR_LEVEL, 0,
6097 "Can't enable both use_direct_io_for_flush_and_compaction "
6098 "and allow_mmap_writes\n");
6099
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(HA_EXIT_FAILURE);
6100 }
6101
6102
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 926 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 926 times.
926 if (rocksdb_db_options->allow_mmap_writes &&
6103 rocksdb_flush_log_at_trx_commit != FLUSH_LOG_NEVER) {
6104 LogPluginErrMsg(ERROR_LEVEL, 0,
6105 "rocksdb_flush_log_at_trx_commit needs to be 0 to use "
6106 "allow_mmap_writes");
6107 DBUG_RETURN(HA_EXIT_FAILURE);
6108 }
6109
6110 // sst_file_manager will move deleted rocksdb sst files to trash_dir
6111 // to be deleted in a background thread.
6112
2/4
✓ Branch 0 taken 926 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 926 times.
✗ Branch 3 not taken.
1852 std::string trash_dir = std::string(rocksdb_datadir) + "/trash";
6113
3/6
✓ Branch 0 taken 926 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 926 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 926 times.
✗ Branch 5 not taken.
1852 rocksdb_db_options->sst_file_manager.reset(NewSstFileManager(
6114 926 rocksdb_db_options->env, myrocks_logger, trash_dir,
6115 rocksdb_sst_mgr_rate_bytes_per_sec, true /* delete_existing_trash */));
6116
6117 926 std::vector<std::string> cf_names;
6118 926 rocksdb::Status status;
6119
2/4
✓ Branch 0 taken 926 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 926 times.
✗ Branch 3 not taken.
1852 status = rocksdb::DB::ListColumnFamilies(*rocksdb_db_options, rocksdb_datadir,
6120 926 &cf_names);
6121
2/6
✓ Branch 0 taken 926 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 926 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
926 DBUG_EXECUTE_IF("rocksdb_init_failure_list_cf", {
6122 // Simulate ListColumnFamilies failure
6123 status = rocksdb::Status::Corruption();
6124 });
6125
3/4
✓ Branch 0 taken 926 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 403 times.
✓ Branch 3 taken 523 times.
926 if (!status.ok()) {
6126 /*
6127 When we start on an empty datadir, ListColumnFamilies returns IOError
6128 with subcode = kPathNotFound.
6129 */
6130
2/4
✓ Branch 0 taken 403 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 403 times.
✗ Branch 3 not taken.
403 if (status.IsPathNotFound()) {
6131
9/18
✓ Branch 0 taken 403 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 403 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 403 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 403 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 403 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 403 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 403 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 403 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 403 times.
✗ Branch 17 not taken.
403 LogPluginErrMsg(
6132 INFORMATION_LEVEL, 0,
6133 "Got kPathNotFound when listing column families assuming that "
6134 "we're creating a new database");
6135 } else {
6136 rdb_log_status_error(status, "Error listing column families");
6137 DBUG_RETURN(HA_EXIT_FAILURE);
6138 }
6139 } else {
6140
9/18
✓ Branch 0 taken 523 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 523 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 523 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 523 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 523 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 523 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 523 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 523 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 523 times.
✗ Branch 17 not taken.
523 LogPluginErrMsg(INFORMATION_LEVEL, 0, "%ld column families found",
6141 cf_names.size());
6142 }
6143
6144 926 std::vector<rocksdb::ColumnFamilyDescriptor> cf_descr;
6145 926 std::vector<rocksdb::ColumnFamilyHandle *> cf_handles;
6146
6147 1852 rocksdb_tbl_options->index_type =
6148 926 (rocksdb::BlockBasedTableOptions::IndexType)rocksdb_index_type;
6149
6150
1/2
✓ Branch 0 taken 926 times.
✗ Branch 1 not taken.
926 if (!rocksdb_tbl_options->no_block_cache) {
6151 926 std::shared_ptr<rocksdb::MemoryAllocator> memory_allocator;
6152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 926 times.
926 if (!rocksdb_cache_dump) {
6153 #ifdef HAVE_JEMALLOC
6154 size_t block_size = rocksdb_tbl_options->block_size;
6155 rocksdb::JemallocAllocatorOptions alloc_opt;
6156 // Limit jemalloc tcache memory usage. The range
6157 // [block_size/4, block_size] should be enough to cover most of
6158 // block cache allocation sizes.
6159 alloc_opt.limit_tcache_size = true;
6160 alloc_opt.tcache_size_lower_bound = block_size / 4;
6161 alloc_opt.tcache_size_upper_bound = block_size;
6162 rocksdb::Status new_alloc_status =
6163 rocksdb::NewJemallocNodumpAllocator(alloc_opt, &memory_allocator);
6164 if (!new_alloc_status.ok()) {
6165 // Fallback to use default malloc/free.
6166 rdb_log_status_error(new_alloc_status,
6167 "Error excluding block cache from core dump");
6168 memory_allocator = nullptr;
6169 DBUG_RETURN(HA_EXIT_FAILURE);
6170 }
6171 #else
6172 // NO_LINT_DEBUG
6173 LogPluginErrMsg(
6174 WARNING_LEVEL, 0,
6175 "Ignoring rocksdb_cache_dump because jemalloc is missing.");
6176 #endif // HAVE_JEMALLOC
6177 }
6178 std::shared_ptr<rocksdb::Cache> block_cache = rocksdb::NewLRUCache(
6179 rocksdb_block_cache_size, -1 /*num_shard_bits*/,
6180 false /*strict_capcity_limit*/, rocksdb_cache_high_pri_pool_ratio,
6181
1/2
✓ Branch 0 taken 926 times.
✗ Branch 1 not taken.
926 memory_allocator);
6182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 926 times.
926 if (rocksdb_sim_cache_size > 0) {
6183 // Simulated cache enabled
6184 // Wrap block cache inside a simulated cache and pass it to RocksDB
6185 rocksdb_tbl_options->block_cache =
6186 rocksdb::NewSimCache(block_cache, rocksdb_sim_cache_size, 6);
6187 } else {
6188 // Pass block cache to RocksDB
6189 926 rocksdb_tbl_options->block_cache = block_cache;
6190 }
6191 926 }
6192
6193
1/2
✓ Branch 0 taken 926 times.
✗ Branch 1 not taken.
926 if (rocksdb_collect_sst_properties) {
6194 properties_collector_factory =
6195
1/2
✓ Branch 0 taken 926 times.
✗ Branch 1 not taken.
926 std::make_shared<Rdb_tbl_prop_coll_factory>(&ddl_manager);
6196
6197 926 rocksdb_set_compaction_options(nullptr, nullptr, nullptr, nullptr);
6198
6199
2/4
✓ Branch 0 taken 926 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 926 times.
✗ Branch 3 not taken.
926 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
6200
6201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 926 times.
926 assert(rocksdb_table_stats_sampling_pct <= RDB_TBL_STATS_SAMPLE_PCT_MAX);
6202 926 properties_collector_factory->SetTableStatsSamplingPct(
6203 rocksdb_table_stats_sampling_pct);
6204
6205
2/4
✓ Branch 0 taken 926 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 926 times.
✗ Branch 3 not taken.
926 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
6206 }
6207
6208
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 914 times.
926 if (rocksdb_persistent_cache_size_mb > 0) {
6209 // TODO: This is the limitations in RocksDB.
6210 // 1. Persistent cache size RocksDB has to be at least cache_file_size.
6211 //
6212 // utilities/persistent_cache/persistent_cache_tier.h:112
6213 // Status ValidateSettings() const {
6214 // ...
6215 // if (cache_size < cache_file_size ...) {
6216 // ...
6217 // cache_file_size is set here.
6218 //
6219 // utilities/persistent_cache/persistent_cache_tier.h:165
6220 // uint32_t cache_file_size = 100ULL * 1024 * 1024;
6221 //
6222 // 2. rocksdb_persistent_cache_path required persistent cache parameter
6223 //
6224 // utilities/persistent_cache/persistent_cache_tier.h:104
6225 // Status ValidateSettings() const {
6226 // ...
6227 // if (!env || path.empty()) {
6228 // ...
6229 static constexpr int persistent_cache_size_mb_min = 100;
6230
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
12 if (rocksdb_persistent_cache_size_mb < persistent_cache_size_mb_min) {
6231
9/18
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LogPluginErrMsg(ERROR_LEVEL, 0,
6232 "Invalid value for rocksdb_persistent_cache_size_mb. It "
6233 "has to be at least %i",
6234 persistent_cache_size_mb_min);
6235
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 DBUG_RETURN(HA_EXIT_FAILURE);
6236 }
6237
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if (!strlen(rocksdb_persistent_cache_path)) {
6238
9/18
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LogPluginErrMsg(ERROR_LEVEL, 0,
6239 "Specify rocksdb_persistent_cache_size_path");
6240
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(HA_EXIT_FAILURE);
6241 }
6242
6243 6 std::shared_ptr<rocksdb::PersistentCache> pcache;
6244 6 uint64_t cache_size_bytes = rocksdb_persistent_cache_size_mb * 1024 * 1024;
6245
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
18 status = rocksdb::NewPersistentCache(
6246
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 rocksdb_db_options->env, std::string(rocksdb_persistent_cache_path),
6247 6 cache_size_bytes, myrocks_logger, true, &pcache);
6248
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (!status.ok()) {
6249 LogPluginErrMsg(ERROR_LEVEL, 0, "Persistent cache returned error: (%s)",
6250 status.getState());
6251 DBUG_RETURN(HA_EXIT_FAILURE);
6252 }
6253 6 rocksdb_tbl_options->persistent_cache = pcache;
6254
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 914 times.
920 } else if (strlen(rocksdb_persistent_cache_path)) {
6255 LogPluginErrMsg(ERROR_LEVEL, 0,
6256 "ust specify rocksdb_persistent_cache_size_mb");
6257 DBUG_RETURN(HA_EXIT_FAILURE);
6258 }
6259
6260
2/6
✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 920 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
920 DBUG_EXECUTE_IF("rocksdb_init_failure_cache", {
6261 DBUG_RETURN(HA_EXIT_FAILURE);
6262 });
6263
6264
2/4
✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 920 times.
✗ Branch 3 not taken.
920 std::unique_ptr<Rdb_cf_options> cf_options_map(new Rdb_cf_options());
6265
2/4
✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 920 times.
920 if (!cf_options_map->init(*rocksdb_tbl_options, properties_collector_factory,
6266 rocksdb_default_cf_options,
6267 rocksdb_override_cf_options)) {
6268 LogPluginErrMsg(ERROR_LEVEL, 0, "Failed to initialize CF options map.");
6269 DBUG_RETURN(HA_EXIT_FAILURE);
6270 }
6271
6272
2/6
✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 920 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
920 DBUG_EXECUTE_IF("rocksdb_init_failure_cf_options", {
6273 DBUG_RETURN(HA_EXIT_FAILURE);
6274 });
6275
6276 /*
6277 If there are no column families, we're creating the new database.
6278 Create one column family named "default".
6279 */
6280
3/4
✓ Branch 0 taken 403 times.
✓ Branch 1 taken 517 times.
✓ Branch 2 taken 403 times.
✗ Branch 3 not taken.
920 if (cf_names.size() == 0) cf_names.push_back(DEFAULT_CF_NAME);
6281
6282 920 std::set<std::string> prev_compaction_enabled_cf_names;
6283
9/18
✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 920 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 920 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 920 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 920 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 920 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 920 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 920 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 920 times.
✗ Branch 17 not taken.
920 LogPluginErrMsg(INFORMATION_LEVEL, 0, "Column Families at start:");
6284
2/2
✓ Branch 0 taken 2714 times.
✓ Branch 1 taken 920 times.
3634 for (size_t i = 0; i < cf_names.size(); ++i) {
6285
1/2
✓ Branch 0 taken 2714 times.
✗ Branch 1 not taken.
2714 rocksdb::ColumnFamilyOptions opts;
6286
1/2
✓ Branch 0 taken 2714 times.
✗ Branch 1 not taken.
2714 cf_options_map->get_cf_options(cf_names[i], &opts);
6287
6288
9/18
✓ Branch 0 taken 2714 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2714 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2714 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2714 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2714 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2714 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2714 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2714 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2714 times.
✗ Branch 17 not taken.
2714 LogPluginErrMsg(INFORMATION_LEVEL, 0, " cf=%s", cf_names[i].c_str());
6289
9/18
✓ Branch 0 taken 2714 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2714 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2714 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2714 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2714 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2714 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2714 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2714 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2714 times.
✗ Branch 17 not taken.
2714 LogPluginErrMsg(INFORMATION_LEVEL, 0, " write_buffer_size=%ld",
6290 opts.write_buffer_size);
6291
9/18
✓ Branch 0 taken 2714 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2714 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2714 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2714 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2714 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2714 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2714 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2714 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2714 times.
✗ Branch 17 not taken.
2714 LogPluginErrMsg(INFORMATION_LEVEL, 0, " target_file_size_base=%" PRIu64,
6292 opts.target_file_size_base);
6293
6294 /*
6295 Temporarily disable compactions to prevent a race condition where
6296 compaction starts before compaction filter is ready.
6297 */
6298
2/2
✓ Branch 0 taken 2672 times.
✓ Branch 1 taken 42 times.
2714 if (!opts.disable_auto_compactions) {
6299
1/2
✓ Branch 0 taken 2672 times.
✗ Branch 1 not taken.
2672 prev_compaction_enabled_cf_names.insert(cf_names[i]);
6300 2672 opts.disable_auto_compactions = true;
6301 }
6302
2/4
✓ Branch 0 taken 2714 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2714 times.
✗ Branch 3 not taken.
2714 cf_descr.push_back(rocksdb::ColumnFamilyDescriptor(cf_names[i], opts));
6303 2714 }
6304
6305 920 rocksdb::Options main_opts(*rocksdb_db_options,
6306
1/2
✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
1840 cf_options_map->get_defaults());
6307
6308 920 rocksdb::TransactionDBOptions tx_db_options;
6309 920 tx_db_options.transaction_lock_timeout = 2000; // 2 seconds
6310
1/2
✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
920 tx_db_options.custom_mutex_factory = std::make_shared<Rdb_mutex_factory>();
6311 920 tx_db_options.write_policy =
6312 920 static_cast<rocksdb::TxnDBWritePolicy>(rocksdb_write_policy);
6313
6314 status =
6315
1/2
✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
920 check_rocksdb_options_compatibility(rocksdb_datadir, main_opts, cf_descr);
6316
6317
2/6
✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 920 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
920 DBUG_EXECUTE_IF("rocksdb_init_failure_incompatible_options", {
6318 // Simulate ListColumnFamilies failure
6319 status = rocksdb::Status::Corruption();
6320 });
6321
6322 // We won't start if we'll determine that there's a chance of data corruption
6323 // because of incompatible options.
6324
3/4
✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 917 times.
920 if (!status.ok()) {
6325
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 rdb_log_status_error(
6326 status, "Compatibility check against existing database options failed");
6327
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(HA_EXIT_FAILURE);
6328 }
6329
6330
9/18
✓ Branch 0 taken 917 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 917 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 917 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 917 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 917 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 917 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 917 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 917 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 917 times.
✗ Branch 17 not taken.
917 LogPluginErrMsg(INFORMATION_LEVEL, 0, "Opening TransactionDB...");
6331
6332
2/4
✓ Branch 0 taken 917 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 917 times.
✗ Branch 3 not taken.
1834 status = rocksdb::TransactionDB::Open(
6333 917 main_opts, tx_db_options, rocksdb_datadir, cf_descr, &cf_handles, &rdb);
6334
6335
2/10
✓ Branch 0 taken 917 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 917 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
917 DBUG_EXECUTE_IF("rocksdb_init_failure_open_db", {
6336 // Simulate opening TransactionDB failure
6337 status = rocksdb::Status::Corruption();
6338 // fix a memory leak caused by not calling cf_manager.init()
6339 for (auto cfh_ptr : cf_handles) delete (cfh_ptr);
6340 });
6341
6342
3/4
✓ Branch 0 taken 917 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 902 times.
917 if (!status.ok()) {
6343
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 rdb_log_status_error(status, "Error opening instance");
6344
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 DBUG_RETURN(HA_EXIT_FAILURE);
6345 }
6346
6347
9/18
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 902 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 902 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 902 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 902 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 902 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 902 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 902 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 902 times.
✗ Branch 17 not taken.
902 LogPluginErrMsg(INFORMATION_LEVEL, 0, "Init column families...");
6348
3/6
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 902 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 902 times.
902 if (st_rdb_exec_time.exec("cf_manager::init", [&]() {
6349 902 return cf_manager.init(rdb, std::move(cf_options_map), &cf_handles);
6350 })) {
6351 LogPluginErrMsg(ERROR_LEVEL, 0, "Failed to init column families.");
6352 DBUG_RETURN(HA_EXIT_FAILURE);
6353 }
6354
6355
9/18
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 902 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 902 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 902 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 902 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 902 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 902 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 902 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 902 times.
✗ Branch 17 not taken.
902 LogPluginErrMsg(INFORMATION_LEVEL, 0, "Initializing data dictionary...");
6356
3/6
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 902 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 902 times.
902 if (st_rdb_exec_time.exec("Rdb_dict_manager_selector::init", [&]() {
6357 902 return dict_manager.init(rdb, &cf_manager,
6358 902 rocksdb_enable_remove_orphaned_dropped_cfs);
6359 })) {
6360 LogPluginErrMsg(ERROR_LEVEL, 0, "Failed to initialize data dictionary.");
6361 DBUG_RETURN(HA_EXIT_FAILURE);
6362 }
6363
6364
9/18
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 902 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 902 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 902 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 902 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 902 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 902 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 902 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 902 times.
✗ Branch 17 not taken.
902 LogPluginErrMsg(INFORMATION_LEVEL, 0, "Initializing DDL Manager...");
6365
3/6
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 902 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 902 times.
902 if (st_rdb_exec_time.exec("Rdb_ddl_manager::init", [&]() {
6366 #if defined(ROCKSDB_INCLUDE_VALIDATE_TABLES) && ROCKSDB_INCLUDE_VALIDATE_TABLES
6367 902 return ddl_manager.init(&dict_manager, &cf_manager,
6368 902 rocksdb_validate_tables);
6369 #else
6370 return ddl_manager.init(&dict_manager, &cf_manager);
6371 #endif // defined(ROCKSDB_INCLUDE_VALIDATE_TABLES) &&
6372 // ROCKSDB_INCLUDE_VALIDATE_TABLES
6373 })) {
6374 LogPluginErrMsg(ERROR_LEVEL, 0, "Failed to initialize DDL manager.");
6375 DBUG_RETURN(HA_EXIT_FAILURE);
6376 }
6377
6378
3/4
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3043 times.
✓ Branch 3 taken 902 times.
3945 for (const auto &cf_handle : cf_manager.get_all_cf()) {
6379 uint flags;
6380
1/2
✓ Branch 0 taken 3043 times.
✗ Branch 1 not taken.
3043 auto local_dict_manager = dict_manager.get_dict_manager_selector_non_const(
6381 false /*is_tmp_table*/);
6382
3/6
✓ Branch 0 taken 3043 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3043 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3043 times.
3043 if (!local_dict_manager->get_cf_flags(cf_handle->GetID(), &flags)) {
6383 const std::unique_ptr<rocksdb::WriteBatch> wb =
6384 local_dict_manager->begin();
6385 rocksdb::WriteBatch *const batch = wb.get();
6386 local_dict_manager->add_cf_flags(batch, cf_handle->GetID(), 0);
6387 local_dict_manager->commit(batch);
6388 }
6389 902 }
6390
6391
2/6
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 902 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
902 DBUG_EXECUTE_IF("rocksdb_init_failure_managers",
6392 { DBUG_RETURN(HA_EXIT_FAILURE); });
6393
6394
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 Rdb_sst_info::init(rdb);
6395
6396 /*
6397 Enable auto compaction, things needed for compaction filter are finished
6398 initializing
6399 */
6400 902 std::vector<rocksdb::ColumnFamilyHandle *> new_compaction_enabled_cf_handles;
6401
2/2
✓ Branch 0 taken 3043 times.
✓ Branch 1 taken 902 times.
3945 for (auto cfh_ptr : cf_handles) {
6402
2/4
✓ Branch 0 taken 3043 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3043 times.
✗ Branch 3 not taken.
3043 if (prev_compaction_enabled_cf_names.find(cfh_ptr->GetName()) !=
6403
2/2
✓ Branch 0 taken 2592 times.
✓ Branch 1 taken 451 times.
6086 prev_compaction_enabled_cf_names.end()) {
6404
1/2
✓ Branch 0 taken 2592 times.
✗ Branch 1 not taken.
2592 new_compaction_enabled_cf_handles.push_back(cfh_ptr);
6405 }
6406 }
6407
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 status = rdb->EnableAutoCompaction(new_compaction_enabled_cf_handles);
6408
6409
2/4
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 902 times.
902 if (!status.ok()) {
6410 rdb_log_status_error(status, "Error enabling compaction");
6411 DBUG_RETURN(HA_EXIT_FAILURE);
6412 }
6413
6414
2/4
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 902 times.
✗ Branch 3 not taken.
902 auto err = rdb_bg_thread.create_thread(BG_THREAD_NAME
6415 #ifdef HAVE_PSI_INTERFACE
6416 ,
6417 rdb_background_psi_thread_key
6418 #endif
6419 );
6420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 902 times.
902 if (err != 0) {
6421 LogPluginErrMsg(ERROR_LEVEL, 0,
6422 "Couldn't start the background thread: (errno=%d)", err);
6423 DBUG_RETURN(HA_EXIT_FAILURE);
6424 }
6425
6426
2/4
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 902 times.
✗ Branch 3 not taken.
902 err = rdb_drop_idx_thread.create_thread(INDEX_THREAD_NAME
6427 #ifdef HAVE_PSI_INTERFACE
6428 ,
6429 rdb_drop_idx_psi_thread_key
6430 #endif
6431 );
6432
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 902 times.
902 if (err != 0) {
6433 LogPluginErrMsg(ERROR_LEVEL, 0,
6434 "Couldn't start the drop index thread: (errno=%d)", err);
6435 DBUG_RETURN(HA_EXIT_FAILURE);
6436 }
6437
6438 #ifndef HAVE_PSI_INTERFACE
6439 err = rdb_is_thread.create_thread(INDEX_STATS_THREAD_NAME);
6440 #else
6441
2/4
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 902 times.
✗ Branch 3 not taken.
902 err = rdb_is_thread.create_thread(INDEX_STATS_THREAD_NAME,
6442 rdb_is_psi_thread_key);
6443 #endif
6444
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 902 times.
902 if (err != 0) {
6445 LogPluginErrMsg(
6446 ERROR_LEVEL, 0,
6447 "Couldn't start the index stats calculation thread: (errno=%d)", err);
6448 DBUG_RETURN(HA_EXIT_FAILURE);
6449 }
6450
6451
2/4
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 902 times.
✗ Branch 3 not taken.
902 err = rdb_mc_thread.create_thread(MANUAL_COMPACTION_THREAD_NAME
6452 #ifdef HAVE_PSI_INTERFACE
6453 ,
6454 rdb_mc_psi_thread_key
6455 #endif
6456 );
6457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 902 times.
902 if (err != 0) {
6458 // NO_LINT_DEBUG
6459 LogPluginErrMsg(ERROR_LEVEL, 0,
6460 "Couldn't start the manual compaction thread: (errno=%d)",
6461 err);
6462 DBUG_RETURN(HA_EXIT_FAILURE);
6463 }
6464
6465
2/6
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 902 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
902 DBUG_EXECUTE_IF("rocksdb_init_failure_threads",
6466 { DBUG_RETURN(HA_EXIT_FAILURE); });
6467
6468
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 rdb_set_collation_exception_list(rocksdb_strict_collation_exceptions);
6469
6470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 902 times.
902 if (rocksdb_pause_background_work) {
6471 rdb->PauseBackgroundWork();
6472 }
6473
6474
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 err = my_error_register(rdb_get_error_messages, HA_ERR_ROCKSDB_FIRST,
6475 HA_ERR_ROCKSDB_LAST);
6476
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 902 times.
902 if (err != 0) {
6477 LogPluginErrMsg(ERROR_LEVEL, 0, "Couldn't initialize error messages");
6478 DBUG_RETURN(HA_EXIT_FAILURE);
6479 }
6480
6481 // Creating an instance of HistogramImpl should only happen after RocksDB
6482 // has been successfully initialized.
6483
2/4
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 902 times.
✗ Branch 3 not taken.
902 commit_latency_stats = new rocksdb::HistogramImpl();
6484
6485 // succeeded, set the init status flag
6486
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 rdb_get_hton_init_state()->set_initialized(true);
6487
6488
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 compaction_stats.resize_history(rocksdb_max_compaction_history);
6489
6490 // Remove tables that may have been leftover during truncation
6491
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 rocksdb_truncation_table_cleanup();
6492
6493 // NO_LINT_DEBUG
6494
9/18
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 902 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 902 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 902 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 902 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 902 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 902 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 902 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 902 times.
✗ Branch 17 not taken.
902 LogPluginErrMsg(INFORMATION_LEVEL, 0,
6495 "MyRocks storage engine plugin has been successfully "
6496 "initialized.");
6497
6498
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 st_rdb_exec_time.report();
6499
6500 // Skip cleaning up rdb_open_tables as we've succeeded
6501 902 rdb_open_tables_cleanup.skip();
6502
6503
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 rocksdb_set_max_bottom_pri_background_compactions_internal(
6504 rocksdb_max_bottom_pri_background_compactions);
6505
6506
2/6
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 902 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
902 DBUG_EXECUTE_IF("rocksdb_init_failure_everything_initialized",
6507 { DBUG_RETURN(HA_EXIT_FAILURE); });
6508
6509
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 DBUG_RETURN(HA_EXIT_SUCCESS);
6510 935 }
6511
6512 // This function cleans up after both normal and init-failure scenarios.
6513 // It can be unsafe to perform some cleanup after initalization failure,
6514 // so currently only some code is executed for such scenarios.
6515 // More code will be safeguarded and executed for both scenarios, and
6516 // eventually minimalShutdown parameter will be removed (always = false).
6517 // @parameter minimalShutdown - only perform uninitialization deemed safe
6518 // (experimentation).
6519 899 static int rocksdb_shutdown(bool minimalShutdown) {
6520 899 int error = 0;
6521
6522 // If we finalize the storage engine plugin, it is no longer initialized.
6523 // Grab a writer lock for the duration of the call, so we can clear the flag
6524 // and destroy the handlerton and global state in isolation.
6525
2/4
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 899 times.
✗ Branch 3 not taken.
899 Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(), true);
6526
6527
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 if (!minimalShutdown) {
6528 // signal the drop index thread to stop
6529
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 rdb_drop_idx_thread.signal(true);
6530
6531 // Flush all memtables for not losing data, even if WAL is disabled.
6532
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 rocksdb_flush_all_memtables();
6533
6534 // Stop all rocksdb background work
6535
6/8
✓ Branch 0 taken 866 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 866 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 866 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 866 times.
✓ Branch 7 taken 33 times.
899 if (rdb && rdb->GetBaseDB()) {
6536
2/4
✓ Branch 0 taken 866 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 866 times.
✗ Branch 3 not taken.
866 CancelAllBackgroundWork(rdb->GetBaseDB(), true);
6537 }
6538
6539 // Signal the background thread to stop and to persist all stats collected
6540 // from background flushes and compactions. This will add more keys to a new
6541 // memtable, but since the memtables were just flushed, it should not
6542 // trigger a flush that can stall due to background threads being stopped.
6543 // As long as these keys are stored in a WAL file, they can be retrieved on
6544 // restart.
6545
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 rdb_bg_thread.signal(true);
6546
6547 // signal the index stats calculation thread to stop
6548
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 rdb_is_thread.signal(true);
6549
6550 // signal the manual compaction thread to stop
6551
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 rdb_mc_thread.signal(true);
6552
6553 // Wait for the background thread to finish.
6554
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 auto err = rdb_bg_thread.join();
6555
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 866 times.
899 if (err != 0) {
6556 // We'll log the message and continue because we're shutting down and
6557 // continuation is the optimal strategy.
6558
9/18
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 33 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 33 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 33 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 33 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 33 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 33 times.
✗ Branch 17 not taken.
33 LogPluginErrMsg(ERROR_LEVEL, 0,
6559 "Couldn't stop the background thread: (errno=%d)", err);
6560 }
6561
6562 // Wait for the drop index thread to finish.
6563
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 err = rdb_drop_idx_thread.join();
6564
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 866 times.
899 if (err != 0) {
6565
9/18
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 33 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 33 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 33 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 33 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 33 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 33 times.
✗ Branch 17 not taken.
33 LogPluginErrMsg(ERROR_LEVEL, 0,
6566 "Couldn't stop the index thread: (errno=%d)", err);
6567 }
6568
6569 // Wait for the index stats calculation thread to finish.
6570
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 err = rdb_is_thread.join();
6571
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 866 times.
899 if (err != 0) {
6572
9/18
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 33 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 33 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 33 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 33 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 33 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 33 times.
✗ Branch 17 not taken.
33 LogPluginErrMsg(
6573 ERROR_LEVEL, 0,
6574 "Couldn't stop the index stats calculation thread: (errno=%d)", err);
6575 }
6576
6577 // Wait for the manual compaction thread to finish.
6578
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 err = rdb_mc_thread.join();
6579
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 866 times.
899 if (err != 0) {
6580
9/18
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 33 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 33 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 33 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 33 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 33 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 33 times.
✗ Branch 17 not taken.
33 LogPluginErrMsg(ERROR_LEVEL, 0,
6581 "Couldn't stop the manual compaction thread: (errno=%d)",
6582 err);
6583 }
6584
6585
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 899 times.
899 if (rdb_open_tables.count()) {
6586 // Looks like we are getting unloaded and yet we have some open tables
6587 // left behind.
6588
6589 LogPluginErrMsg(ERROR_LEVEL, 0,
6590 "There're tables still opened during shutdown");
6591 error = 1;
6592 }
6593
6594
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 rdb_open_tables.free();
6595 }
6596
6597 // The only code executed during both normal and init faiure shutdown are
6598 // deleting mutexes. The plan is to gradually increase this section so there's
6599 // one single shutdown function for all scenarios.
6600
6601
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 rdb_sysvars_mutex.destroy();
6602
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 rdb_block_cache_resize_mutex.destroy();
6603
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 rdb_bottom_pri_background_compactions_resize_mutex.destroy();
6604
6605
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 if (!minimalShutdown) {
6606
2/2
✓ Branch 0 taken 896 times.
✓ Branch 1 taken 3 times.
899 delete rdb_collation_exceptions;
6607 899 rdb_collation_exceptions = nullptr;
6608 }
6609
6610
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 rdb_collation_data_mutex.destroy();
6611
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 rdb_mem_cmp_space_mutex.destroy();
6612
6613
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 Rdb_transaction::term_mutex();
6614
6615
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 if (!minimalShutdown) {
6616
2/2
✓ Branch 0 taken 1841152 times.
✓ Branch 1 taken 899 times.
1842051 for (auto &it : rdb_collation_data) {
6617
2/2
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 1840952 times.
1841152 delete it;
6618 1841152 it = nullptr;
6619 }
6620
6621
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 ddl_manager.cleanup();
6622
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 dict_manager.cleanup();
6623
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 cf_manager.cleanup();
6624
6625
2/2
✓ Branch 0 taken 866 times.
✓ Branch 1 taken 33 times.
899 delete rdb;
6626 899 rdb = nullptr;
6627
6628
2/2
✓ Branch 0 taken 866 times.
✓ Branch 1 taken 33 times.
899 delete commit_latency_stats;
6629 899 commit_latency_stats = nullptr;
6630
6631 // Disown the cache data since we're shutting down.
6632 // This results in memory leaks but it improved the shutdown time.
6633 // Don't disown when running under valgrind
6634 #ifndef HAVE_VALGRIND
6635
2/2
✓ Branch 0 taken 890 times.
✓ Branch 1 taken 9 times.
899 if (rocksdb_tbl_options->block_cache) {
6636
1/2
✓ Branch 0 taken 890 times.
✗ Branch 1 not taken.
890 rocksdb_tbl_options->block_cache->DisownData();
6637 }
6638 #endif /* HAVE_VALGRIND */
6639 }
6640
6641 899 rocksdb_db_options = nullptr;
6642 899 rocksdb_tbl_options = nullptr;
6643 899 rocksdb_stats = nullptr;
6644
6645
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 if (!minimalShutdown) {
6646
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 my_error_unregister(HA_ERR_ROCKSDB_FIRST, HA_ERR_ROCKSDB_LAST);
6647 }
6648
6649
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 deinit_logging_service_for_plugin(&reg_srv, &log_bi, &log_bs);
6650
6651 // clear the initialized flag and unlock
6652
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 rdb_get_hton_init_state()->set_initialized(false);
6653
6654 899 return error;
6655 899 }
6656
6657 /*
6658 Storage Engine deinitialization function, invoked when plugin is unloaded.
6659 */
6660
6661 899 static int rocksdb_done_func(void *const p MY_ATTRIBUTE((__unused__))) {
6662
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 DBUG_ENTER_FUNC();
6663
6664
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 int error = rocksdb_shutdown(/* minimalShutdown = */ false);
6665
6666
1/2
✓ Branch 0 taken 899 times.
✗ Branch 1 not taken.
899 DBUG_RETURN(error);
6667 }
6668
6669 935 static int rocksdb_init_func(void *const p) {
6670 935 int ret = rocksdb_init_internal(p);
6671
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 902 times.
935 if (ret) {
6672 33 rocksdb_done_func(p);
6673 }
6674 935 return ret;
6675 }
6676
6677 // If the iterator is not valid it might be because of EOF but might be due
6678 // to IOError or corruption. The good practice is always check it.
6679 // https://github.com/facebook/rocksdb/wiki/Iterator#error-handling
6680 197093181 bool is_valid_iterator(rocksdb::Iterator *scan_it) {
6681
2/2
✓ Branch 0 taken 196840575 times.
✓ Branch 1 taken 252606 times.
197093181 if (scan_it->Valid()) {
6682 196840575 return true;
6683 } else {
6684
1/2
✓ Branch 0 taken 252606 times.
✗ Branch 1 not taken.
252606 rocksdb::Status s = scan_it->status();
6685
2/6
✓ Branch 0 taken 252606 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 252606 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
252606 DBUG_EXECUTE_IF("rocksdb_return_status_corrupted",
6686 dbug_change_status_to_corrupted(&s););
6687
5/10
✓ Branch 0 taken 252606 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 252606 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 252606 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 252606 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 252606 times.
252606 if (s.IsIOError() || s.IsCorruption()) {
6688 if (s.IsCorruption()) {
6689 rdb_persist_corruption_marker();
6690 }
6691 rdb_handle_io_error(s, RDB_IO_ERROR_GENERAL);
6692 }
6693 252606 return false;
6694 252606 }
6695 }
6696
6697 /**
6698 @brief
6699 Example of simple lock controls. The "table_handler" it creates is a
6700 structure we will pass to each ha_rocksdb handler. Do you have to have
6701 one of these? Well, you have pieces that are used for locking, and
6702 they are needed to function.
6703 */
6704
6705 24070 Rdb_table_handler *Rdb_open_tables_map::get_table_handler(
6706 const char *const table_name) {
6707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24070 times.
24070 assert(table_name != nullptr);
6708
6709 Rdb_table_handler *table_handler;
6710
6711
1/2
✓ Branch 0 taken 24070 times.
✗ Branch 1 not taken.
24070 const std::string table_name_str(table_name);
6712
6713 // First, look up the table in the hash map.
6714
2/4
✓ Branch 0 taken 24070 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24070 times.
✗ Branch 3 not taken.
24070 RDB_MUTEX_LOCK_CHECK(m_mutex);
6715
1/2
✓ Branch 0 taken 24070 times.
✗ Branch 1 not taken.
24070 const auto &it = m_table_map.find(table_name_str);
6716
2/2
✓ Branch 0 taken 6149 times.
✓ Branch 1 taken 17921 times.
24070 if (it != m_table_map.end()) {
6717 // Found it
6718 6149 table_handler = it->second;
6719 } else {
6720 char *tmp_name;
6721
6722 // Since we did not find it in the hash map, attempt to create and add it
6723 // to the hash map.
6724 #ifdef HAVE_PSI_INTERFACE
6725 17921 if (!(table_handler = reinterpret_cast<Rdb_table_handler *>(
6726
2/4
✓ Branch 0 taken 17921 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17921 times.
17921 my_multi_malloc(rdb_handler_memory_key, MYF(MY_WME | MY_ZEROFILL),
6727 &table_handler, sizeof(*table_handler), &tmp_name,
6728 17921 table_name_str.length() + 1, NullS)))) {
6729 #else
6730 if (!(table_handler = reinterpret_cast<Rdb_table_handler *>(
6731 my_multi_malloc(PSI_NOT_INSTRUMENTED, MYF(MY_WME | MY_ZEROFILL),
6732 &table_handler, sizeof(*table_handler), &tmp_name,
6733 table_name_str.length() + 1, NullS)))) {
6734 #endif
6735 // Allocating a new Rdb_table_handler and a new table name failed.
6736 RDB_MUTEX_UNLOCK_CHECK(m_mutex);
6737 return nullptr;
6738 }
6739
6740 17921 table_handler->m_ref_count = 0;
6741 17921 table_handler->m_table_name_length = table_name_str.length();
6742 17921 table_handler->m_table_name = tmp_name;
6743 17921 my_stpmov(table_handler->m_table_name, table_name_str.c_str());
6744
6745
1/2
✓ Branch 0 taken 17921 times.
✗ Branch 1 not taken.
17921 m_table_map.emplace(table_name_str, table_handler);
6746
6747
1/2
✓ Branch 0 taken 17921 times.
✗ Branch 1 not taken.
17921 thr_lock_init(&table_handler->m_thr_lock);
6748
1/2
✓ Branch 0 taken 17921 times.
✗ Branch 1 not taken.
17921 table_handler->m_io_perf_read.init();
6749 }
6750
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24070 times.
24070 assert(table_handler->m_ref_count >= 0);
6751 24070 table_handler->m_ref_count++;
6752
6753
2/4
✓ Branch 0 taken 24070 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24070 times.
✗ Branch 3 not taken.
24070 RDB_MUTEX_UNLOCK_CHECK(m_mutex);
6754
6755 24070 return table_handler;
6756 24070 }
6757
6758 33 std::vector<std::string> rdb_get_open_table_names(void) {
6759 33 return rdb_open_tables.get_table_names();
6760 }
6761
6762 33 std::vector<std::string> Rdb_open_tables_map::get_table_names(void) const {
6763 const Rdb_table_handler *table_handler;
6764 33 std::vector<std::string> names;
6765
6766
2/4
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
33 RDB_MUTEX_LOCK_CHECK(m_mutex);
6767
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 33 times.
87 for (const auto &kv : m_table_map) {
6768 54 table_handler = kv.second;
6769
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 assert(table_handler != nullptr);
6770
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
54 names.push_back(table_handler->m_table_name);
6771 }
6772
2/4
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
33 RDB_MUTEX_UNLOCK_CHECK(m_mutex);
6773
6774 33 return names;
6775 }
6776
6777 /*
6778 Inspired by innobase_get_int_col_max_value from InnoDB. This returns the
6779 maximum value a type can take on.
6780 */
6781 14843455 static ulonglong rdb_get_int_col_max_value(const Field *field) {
6782 14843455 ulonglong max_value = 0;
6783
9/13
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 95 times.
✓ Branch 6 taken 436 times.
✓ Branch 7 taken 14604202 times.
✓ Branch 8 taken 144 times.
✓ Branch 9 taken 251465 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✓ Branch 12 taken 5490 times.
14843455 switch (field->key_type()) {
6784 case HA_KEYTYPE_BINARY:
6785 max_value = 0xFFULL;
6786 break;
6787 24 case HA_KEYTYPE_INT8:
6788 24 max_value = 0x7FULL;
6789 24 break;
6790 case HA_KEYTYPE_USHORT_INT:
6791 max_value = 0xFFFFULL;
6792 break;
6793 60 case HA_KEYTYPE_SHORT_INT:
6794 60 max_value = 0x7FFFULL;
6795 60 break;
6796 case HA_KEYTYPE_UINT24:
6797 max_value = 0xFFFFFFULL;
6798 break;
6799 95 case HA_KEYTYPE_INT24:
6800 95 max_value = 0x7FFFFFULL;
6801 95 break;
6802 436 case HA_KEYTYPE_ULONG_INT:
6803 436 max_value = 0xFFFFFFFFULL;
6804 436 break;
6805 14604202 case HA_KEYTYPE_LONG_INT:
6806 14604202 max_value = 0x7FFFFFFFULL;
6807 14604202 break;
6808 144 case HA_KEYTYPE_ULONGLONG:
6809 144 max_value = 0xFFFFFFFFFFFFFFFFULL;
6810 144 break;
6811 251465 case HA_KEYTYPE_LONGLONG:
6812 251465 max_value = 0x7FFFFFFFFFFFFFFFULL;
6813 251465 break;
6814 case HA_KEYTYPE_FLOAT:
6815 max_value = 0x1000000ULL;
6816 break;
6817 3 case HA_KEYTYPE_DOUBLE:
6818 3 max_value = 0x20000000000000ULL;
6819 3 break;
6820 5490 default:
6821 5490 abort();
6822 }
6823
6824 14856429 return max_value;
6825 }
6826
6827 2068 void ha_rocksdb::load_auto_incr_value() {
6828 2068 ulonglong auto_incr = 0;
6829 2068 bool validate_last = false, use_datadic = true;
6830 #if !defined(NDEBUG)
6831
3/4
✓ Branch 0 taken 2068 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2065 times.
2068 DBUG_EXECUTE_IF("myrocks_autoinc_upgrade", use_datadic = false;);
6832 2068 validate_last = true;
6833 #endif // !defined(NDEBUG)
6834
6835
2/2
✓ Branch 0 taken 2065 times.
✓ Branch 1 taken 3 times.
4133 if (use_datadic &&
6836 dict_manager
6837 .get_dict_manager_selector_const(
6838
1/2
✓ Branch 0 taken 2065 times.
✗ Branch 1 not taken.
2065 m_tbl_def->get_autoincr_gl_index_id().cf_id)
6839
7/10
✓ Branch 0 taken 2065 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2065 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2065 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 431 times.
✓ Branch 7 taken 1634 times.
✓ Branch 8 taken 431 times.
✓ Branch 9 taken 1637 times.
4133 ->get_auto_incr_val(m_tbl_def->get_autoincr_gl_index_id(),
6840 &auto_incr)) {
6841
1/2
✓ Branch 0 taken 431 times.
✗ Branch 1 not taken.
431 update_auto_incr_val(auto_incr);
6842 }
6843
6844 // If we find nothing in the data dictionary, or if we are in debug mode,
6845 // then call index_last to get the last value.
6846 //
6847 // This is needed when upgrading from a server that did not support
6848 // persistent auto_increment, of if the table is empty.
6849 //
6850 // For debug mode, we are just verifying that the data dictionary value is
6851 // greater than or equal to the maximum value in the table.
6852
3/4
✓ Branch 0 taken 431 times.
✓ Branch 1 taken 1637 times.
✓ Branch 2 taken 431 times.
✗ Branch 3 not taken.
2068 if (auto_incr == 0 || validate_last) {
6853
1/2
✓ Branch 0 taken 2068 times.
✗ Branch 1 not taken.
2068 auto_incr = load_auto_incr_value_from_index();
6854
1/2
✓ Branch 0 taken 2068 times.
✗ Branch 1 not taken.
2068 update_auto_incr_val(auto_incr);
6855 }
6856
6857 // If we failed to find anything from the data dictionary and index, then
6858 // initialize auto_increment to 1.
6859
2/2
✓ Branch 0 taken 1626 times.
✓ Branch 1 taken 442 times.
2068 if (m_tbl_def->m_auto_incr_val == 0) {
6860
1/2
✓ Branch 0 taken 1626 times.
✗ Branch 1 not taken.
1626 update_auto_incr_val(1);
6861 }
6862 2068 }
6863
6864 2155 ulonglong ha_rocksdb::load_auto_incr_value_from_index() {
6865 2155 const int save_active_index = active_index;
6866 2155 active_index = table->s->next_number_index;
6867
6868
2/4
✓ Branch 0 taken 2155 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2155 times.
2155 assert(!m_key_descr_arr[active_index_pos()]->is_partial_index());
6869 std::unique_ptr<Rdb_iterator> save_iterator(new Rdb_iterator_base(
6870
4/8
✓ Branch 0 taken 2155 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2155 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2155 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2155 times.
✗ Branch 7 not taken.
4310 ha_thd(), m_key_descr_arr[active_index_pos()], m_pk_descr, m_tbl_def));
6871 2155 std::swap(m_iterator, save_iterator);
6872
6873 2155 ulonglong last_val = 0;
6874
6875
1/2
✓ Branch 0 taken 2155 times.
✗ Branch 1 not taken.
2155 Rdb_transaction *const tx = get_or_create_tx(table->in_use);
6876 2155 const bool is_new_snapshot = !tx->has_snapshot();
6877
1/2
✓ Branch 0 taken 2155 times.
✗ Branch 1 not taken.
2155 if (is_new_snapshot) {
6878
1/2
✓ Branch 0 taken 2155 times.
✗ Branch 1 not taken.
2155 tx->acquire_snapshot(true);
6879 }
6880
6881 // Do a lookup. We only need index column, so it should be index-only.
6882 // (another reason to make it index-only is that table->read_set is not set
6883 // appropriately and non-index-only lookup will not read the value)
6884 2155 const bool save_keyread_only = m_keyread_only;
6885 2155 m_keyread_only = true;
6886 2155 m_converter->set_is_key_requested(true);
6887
6888
3/4
✓ Branch 0 taken 2155 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 413 times.
✓ Branch 3 taken 1742 times.
2155 if (!index_last(table->record[0])) {
6889 413 Field *field =
6890 413 table->key_info[table->s->next_number_index].key_part[0].field;
6891
1/2
✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
413 ulonglong max_val = rdb_get_int_col_max_value(field);
6892 my_bitmap_map *const old_map =
6893 413 dbug_tmp_use_all_columns(table, table->read_set);
6894
1/2
✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
413 last_val = field->val_int();
6895
1/2
✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
413 if (last_val != max_val) {
6896 413 last_val++;
6897 }
6898 #ifndef NDEBUG
6899 ulonglong dd_val;
6900
1/2
✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
413 if (last_val <= max_val) {
6901
1/2
✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
413 const auto &gl_index_id = m_tbl_def->get_autoincr_gl_index_id();
6902 826 if (dict_manager.get_dict_manager_selector_const(gl_index_id.cf_id)
6903
6/8
✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 413 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 410 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 410 times.
✓ Branch 7 taken 3 times.
823 ->get_auto_incr_val(gl_index_id, &dd_val) &&
6904
2/4
✓ Branch 0 taken 410 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 410 times.
✗ Branch 3 not taken.
410 tx->get_auto_incr(gl_index_id) == 0) {
6905
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 410 times.
410 assert(dd_val >= last_val);
6906 }
6907 }
6908 #endif
6909 413 dbug_tmp_restore_column_map(table->read_set, old_map);
6910 }
6911
6912 2155 m_keyread_only = save_keyread_only;
6913
1/2
✓ Branch 0 taken 2155 times.
✗ Branch 1 not taken.
2155 if (is_new_snapshot) {
6914
1/2
✓ Branch 0 taken 2155 times.
✗ Branch 1 not taken.
2155 tx->release_snapshot();
6915 }
6916
6917 2155 active_index = save_active_index;
6918
6919 /*
6920 Do what ha_rocksdb::index_end() does.
6921 (Why don't we use index_init/index_end? class handler defines index_init
6922 as private, for some reason).
6923 */
6924 2155 std::swap(m_iterator, save_iterator);
6925
6926 2155 return last_val;
6927 2155 }
6928
6929 8190165 void ha_rocksdb::update_auto_incr_val(ulonglong val) {
6930 8190165 ulonglong auto_incr_val = m_tbl_def->m_auto_incr_val;
6931 8150539 while (
6932
3/4
✓ Branch 0 taken 1515625 times.
✓ Branch 1 taken 6633248 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8150539 times.
9666164 auto_incr_val < val &&
6933
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1515625 times.
3031250 !m_tbl_def->m_auto_incr_val.compare_exchange_weak(auto_incr_val, val)) {
6934 // Do nothing - just loop until auto_incr_val is >= val or we successfully
6935 // set it
6936 }
6937 8150539 }
6938
6939 8155900 void ha_rocksdb::update_auto_incr_val_from_field() {
6940 Field *field;
6941 ulonglong new_val, max_val;
6942 8155900 field = table->key_info[table->s->next_number_index].key_part[0].field;
6943 8155900 max_val = rdb_get_int_col_max_value(field);
6944
6945 my_bitmap_map *const old_map =
6946 8179923 dbug_tmp_use_all_columns(table, table->read_set);
6947 8166542 new_val = field->val_int();
6948 // don't increment if we would wrap around
6949
1/2
✓ Branch 0 taken 8183373 times.
✗ Branch 1 not taken.
8182315 if (new_val != max_val) {
6950 8183373 new_val++;
6951 }
6952
6953 8182315 dbug_tmp_restore_column_map(table->read_set, old_map);
6954
6955 // Only update if positive value was set for auto_incr column.
6956
1/2
✓ Branch 0 taken 8183657 times.
✗ Branch 1 not taken.
8182156 if (new_val <= max_val) {
6957 8183657 Rdb_transaction *const tx = get_or_create_tx(table->in_use);
6958
1/2
✓ Branch 0 taken 8252588 times.
✗ Branch 1 not taken.
8163975 tx->set_auto_incr(m_tbl_def->get_autoincr_gl_index_id(), new_val);
6959
6960 // Update the in memory auto_incr value in m_tbl_def.
6961 8252588 update_auto_incr_val(new_val);
6962 }
6963 8148934 }
6964
6965 84 int ha_rocksdb::load_hidden_pk_value() {
6966 84 const int save_active_index = active_index;
6967 84 active_index = MAX_KEY;
6968
6969 std::unique_ptr<Rdb_iterator> save_iterator(new Rdb_iterator_base(
6970
4/8
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 84 times.
✗ Branch 7 not taken.
168 ha_thd(), m_key_descr_arr[active_index_pos()], m_pk_descr, m_tbl_def));
6971 84 std::swap(m_iterator, save_iterator);
6972
6973
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 Rdb_transaction *const tx = get_or_create_tx(table->in_use);
6974 84 const bool is_new_snapshot = !tx->has_snapshot();
6975
6976 84 longlong hidden_pk_id = 1;
6977 84 longlong old = 0;
6978 84 int rc = 0;
6979 // Do a lookup.
6980
3/4
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 21 times.
84 if (!index_last(table->record[0])) {
6981 /*
6982 Decode PK field from the key
6983 */
6984
1/2
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
63 rc = read_hidden_pk_id_from_rowkey(&hidden_pk_id);
6985
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
63 if (rc) {
6986 goto exit;
6987 }
6988
6989 63 hidden_pk_id++;
6990 }
6991
6992 84 old = m_tbl_def->m_hidden_pk_val;
6993
2/4
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
168 while (old < hidden_pk_id &&
6994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
168 !m_tbl_def->m_hidden_pk_val.compare_exchange_weak(old, hidden_pk_id)) {
6995 }
6996
6997 84 exit:
6998
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 if (is_new_snapshot) {
6999
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 tx->release_snapshot();
7000 }
7001
7002 84 active_index = save_active_index;
7003 84 std::swap(m_iterator, save_iterator);
7004
7005 84 return rc;
7006 84 }
7007
7008 /* Get PK value from m_tbl_def->m_hidden_pk_info. */
7009 400949 longlong ha_rocksdb::update_hidden_pk_val() {
7010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 400949 times.
400949 assert(has_hidden_pk(table));
7011 400949 const longlong new_val = m_tbl_def->m_hidden_pk_val++;
7012 400949 return new_val;
7013 }
7014
7015 /* Get the id of the hidden pk id from m_last_rowkey */
7016 109298 int ha_rocksdb::read_hidden_pk_id_from_rowkey(longlong *const hidden_pk_id) {
7017
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109298 times.
109298 assert(hidden_pk_id != nullptr);
7018
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109298 times.
109298 assert(table != nullptr);
7019
2/4
✓ Branch 0 taken 109298 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 109298 times.
109298 assert(has_hidden_pk(table));
7020
7021 109298 rocksdb::Slice rowkey_slice(m_last_rowkey.ptr(), m_last_rowkey.length());
7022
7023 // Get hidden primary key from old key slice
7024 109298 Rdb_string_reader reader(&rowkey_slice);
7025
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109298 times.
109298 if ((!reader.read(Rdb_key_def::INDEX_NUMBER_SIZE))) {
7026 return HA_ERR_ROCKSDB_CORRUPT_DATA;
7027 }
7028
7029 109298 const int length = Field_longlong::PACK_LENGTH;
7030 109298 const uchar *from = reinterpret_cast<const uchar *>(reader.read(length));
7031
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109298 times.
109298 if (from == nullptr) {
7032 /* Mem-comparable image doesn't have enough bytes */
7033 return HA_ERR_ROCKSDB_CORRUPT_DATA;
7034 }
7035
7036 109298 *hidden_pk_id = rdb_netbuf_read_uint64(&from);
7037 109298 return HA_EXIT_SUCCESS;
7038 }
7039
7040 /**
7041 @brief
7042 Free lock controls. We call this whenever we close a table. If the table had
7043 the last reference to the table_handler, then we free the memory associated
7044 with it.
7045 */
7046
7047 24020 void Rdb_open_tables_map::release_table_handler(
7048 Rdb_table_handler *const table_handler) {
7049 24020 RDB_MUTEX_LOCK_CHECK(m_mutex);
7050
7051
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24022 times.
24022 assert(table_handler != nullptr);
7052
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24022 times.
24022 assert(table_handler->m_ref_count > 0);
7053
2/2
✓ Branch 0 taken 17879 times.
✓ Branch 1 taken 6143 times.
24022 if (!--table_handler->m_ref_count) {
7054 const auto ret MY_ATTRIBUTE((__unused__)) =
7055
2/4
✓ Branch 0 taken 17879 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17879 times.
✗ Branch 3 not taken.
17879 m_table_map.erase(std::string(table_handler->m_table_name));
7056
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17879 times.
17879 assert(ret == 1); // the hash entry must actually be found and deleted
7057 17879 my_core::thr_lock_delete(&table_handler->m_thr_lock);
7058 17879 my_free(table_handler);
7059 }
7060
7061 24022 RDB_MUTEX_UNLOCK_CHECK(m_mutex);
7062 24022 }
7063
7064 109518 static handler *rocksdb_create_handler(my_core::handlerton *const hton,
7065 my_core::TABLE_SHARE *const table_arg,
7066 bool partitioned,
7067 my_core::MEM_ROOT *const mem_root) {
7068
2/2
✓ Branch 0 taken 10783 times.
✓ Branch 1 taken 98735 times.
109518 if (partitioned) {
7069
2/4
✓ Branch 0 taken 10783 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10783 times.
✗ Branch 3 not taken.
10783 ha_rockspart *file = new (mem_root) ha_rockspart(hton, table_arg);
7070
3/6
✓ Branch 0 taken 10783 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10783 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 10783 times.
10783 if (file && file->init_partitioning(mem_root)) {
7071 destroy(file);
7072 return (nullptr);
7073 }
7074 10783 return (file);
7075 }
7076
7077
2/4
✓ Branch 0 taken 98735 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 98735 times.
✗ Branch 3 not taken.
98735 return new (mem_root) ha_rocksdb(hton, table_arg);
7078 }
7079
7080 131969 ha_rocksdb::ha_rocksdb(my_core::handlerton *const hton,
7081 131969 my_core::TABLE_SHARE *const table_arg)
7082 : handler(hton, table_arg),
7083 131972 m_table_handler(nullptr),
7084 131972 m_tbl_def(nullptr),
7085 131972 m_pk_descr(nullptr),
7086 131972 m_key_descr_arr(nullptr),
7087 131972 m_pk_can_be_decoded(true),
7088 131972 m_pk_packed_tuple(nullptr),
7089 131972 m_sk_packed_tuple(nullptr),
7090 131972 m_end_key_packed_tuple(nullptr),
7091 131973 m_sk_packed_tuple_old(nullptr),
7092 131973 m_pack_buffer(nullptr),
7093 131971 m_lock_rows(RDB_LOCK_NONE),
7094 131971 m_keyread_only(false),
7095 131971 m_iteration_only(false),
7096 131971 m_insert_with_update(false),
7097 131971 m_dup_key_found(false),
7098 #if defined(ROCKSDB_INCLUDE_RFR) && ROCKSDB_INCLUDE_RFR
7099 131972 m_in_rpl_delete_rows(false),
7100 131972 m_in_rpl_update_rows(false),
7101 #endif // defined(ROCKSDB_INCLUDE_RFR) && ROCKSDB_INCLUDE_RFR
7102
3/6
✓ Branch 0 taken 131971 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131971 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 131972 times.
✗ Branch 5 not taken.
263941 m_need_build_decoder(false) {
7103 131972 }
7104
7105 263688 ha_rocksdb::~ha_rocksdb() {
7106 int err MY_ATTRIBUTE((__unused__));
7107 263688 err = finalize_bulk_load(false);
7108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131844 times.
263688 if (err != 0) {
7109 LogPluginErrMsg(ERROR_LEVEL, 0,
7110 "Error %d finalizing bulk load while closing handler.",
7111 err);
7112 }
7113 }
7114
7115 703 const std::string &ha_rocksdb::get_table_basename() const {
7116 703 return m_tbl_def->base_tablename();
7117 }
7118
7119 /**
7120 @return
7121 false OK
7122 other Error inpacking the data
7123 */
7124 30906 bool ha_rocksdb::init_with_fields() {
7125
1/2
✓ Branch 0 taken 30906 times.
✗ Branch 1 not taken.
30906 DBUG_ENTER_FUNC();
7126
7127 30906 const uint pk = table_share->primary_key;
7128
2/2
✓ Branch 0 taken 16945 times.
✓ Branch 1 taken 13961 times.
30906 if (pk != MAX_KEY) {
7129 16945 const uint key_parts = table_share->key_info[pk].user_defined_key_parts;
7130
1/2
✓ Branch 0 taken 16945 times.
✗ Branch 1 not taken.
16945 check_keyread_allowed(m_pk_can_be_decoded, table_share, pk /*PK*/,
7131 key_parts - 1, true);
7132 } else {
7133 13961 m_pk_can_be_decoded = false;
7134 }
7135
1/2
✓ Branch 0 taken 30907 times.
✗ Branch 1 not taken.
30906 cached_table_flags = table_flags();
7136
7137
1/2
✓ Branch 0 taken 30907 times.
✗ Branch 1 not taken.
30907 DBUG_RETURN(false); /* Ok */
7138 }
7139
7140 504 bool ha_rocksdb::allow_unsafe_alter() noexcept {
7141 504 return rocksdb_allow_unsafe_alter;
7142 }
7143
7144 351 bool ha_rocksdb::rpl_can_handle_stm_event() const noexcept {
7145
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 347 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
351 return !(rpl_skip_tx_api_var && !super_read_only);
7146 }
7147
7148 /*
7149 If the key is a TTL key, we may need to filter it out.
7150
7151 The purpose of read filtering for tables with TTL is to ensure that
7152 during a transaction a key which has expired already but not removed by
7153 compaction yet is not returned to the user.
7154
7155 Without this the user might be hit with problems such as disappearing
7156 rows within a transaction, etc, because the compaction filter ignores
7157 snapshots when filtering keys.
7158 */
7159 3987 bool rdb_should_hide_ttl_rec(const Rdb_key_def &kd,
7160 const rocksdb::Slice &ttl_rec_val,
7161 Rdb_transaction *tx) {
7162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3987 times.
3987 assert(kd.has_ttl());
7163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3987 times.
3987 assert(kd.m_ttl_rec_offset != UINT_MAX);
7164 3987 THD *thd = tx->get_thd();
7165 3987 const int64_t curr_ts = tx->m_snapshot_timestamp;
7166
7167 /*
7168 Curr_ts can only be 0 if there are no snapshots open.
7169 should_hide_ttl_rec can only be called when there is >=1 snapshots, unless
7170 we are filtering on the write path (single INSERT/UPDATE) in which case
7171 we are passed in the current time as curr_ts.
7172
7173 In the event curr_ts is 0, we always decide not to filter the record. We
7174 also log a warning and increment a diagnostic counter.
7175 */
7176
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3987 times.
3987 if (curr_ts == 0) {
7177 assert(false);
7178 push_warning_printf(thd, Sql_condition::SL_WARNING, ER_WRONG_ARGUMENTS,
7179 "TTL read filtering called with no snapshot.");
7180 rdb_update_global_stats(ROWS_UNFILTERED_NO_SNAPSHOT, 1);
7181 return false;
7182 }
7183
7184
7/10
✓ Branch 0 taken 3987 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1281 times.
✓ Branch 3 taken 2706 times.
✓ Branch 4 taken 1281 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1281 times.
✓ Branch 8 taken 2706 times.
✓ Branch 9 taken 1281 times.
3987 if (!rdb_is_ttl_read_filtering_enabled() || !rdb_is_ttl_enabled()) {
7185 2706 return false;
7186 }
7187
7188 1281 Rdb_string_reader reader(&ttl_rec_val);
7189
7190 /*
7191 Find where the 8-byte ttl is for each record in this index.
7192 */
7193 uint64 ts;
7194
3/6
✓ Branch 0 taken 1281 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1281 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1281 times.
1281 if (!reader.read(kd.m_ttl_rec_offset) || reader.read_uint64(&ts)) {
7195 /*
7196 This condition should never be reached since all TTL records have an
7197 8 byte ttl field in front. Don't filter the record out, and log an error.
7198 */
7199 std::string buf;
7200 buf = rdb_hexdump(ttl_rec_val.data(), ttl_rec_val.size(),
7201 RDB_MAX_HEXDUMP_LEN);
7202 const GL_INDEX_ID gl_index_id = kd.get_gl_index_id();
7203 LogPluginErrMsg(
7204 ERROR_LEVEL, 0,
7205 "Decoding ttl from PK value failed, for index (%u,%u), val: %s",
7206 gl_index_id.cf_id, gl_index_id.index_id, buf.c_str());
7207 assert(0);
7208 return false;
7209 }
7210
7211 /* Hide record if it has expired before the current snapshot time. */
7212 1281 uint64 read_filter_ts = 0;
7213 #if !defined(NDEBUG)
7214
1/2
✓ Branch 0 taken 1281 times.
✗ Branch 1 not taken.
1281 read_filter_ts += rdb_dbug_set_ttl_read_filter_ts();
7215 #endif // !defined(NDEBUG)
7216 1281 bool is_hide_ttl =
7217 1281 ts + kd.m_ttl_duration + read_filter_ts <= static_cast<uint64>(curr_ts);
7218
2/2
✓ Branch 0 taken 831 times.
✓ Branch 1 taken 450 times.
1281 if (is_hide_ttl) {
7219
1/2
✓ Branch 0 taken 831 times.
✗ Branch 1 not taken.
831 rdb_update_global_stats(ROWS_FILTERED, 1);
7220
7221 /* increment examined row count when rows are skipped */
7222
1/2
✓ Branch 0 taken 831 times.
✗ Branch 1 not taken.
831 thd->inc_examined_row_count(1);
7223
2/4
✓ Branch 0 taken 831 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 831 times.
✗ Branch 3 not taken.
831 DEBUG_SYNC(thd, "rocksdb.ttl_rows_examined");
7224 }
7225 1281 return is_hide_ttl;
7226 }
7227
7228 #ifndef NDEBUG
7229 void dbug_append_garbage_at_end(rocksdb::PinnableSlice *on_disk_rec) {
7230 std::string str(on_disk_rec->data(), on_disk_rec->size());
7231 on_disk_rec->Reset();
7232 str.append("abc");
7233 on_disk_rec->PinSelf(rocksdb::Slice(str));
7234 }
7235
7236 void dbug_truncate_record(rocksdb::PinnableSlice *on_disk_rec) {
7237 on_disk_rec->remove_suffix(on_disk_rec->size());
7238 }
7239
7240 void dbug_modify_rec_varchar12(rocksdb::PinnableSlice *on_disk_rec) {
7241 std::string res;
7242 // The record is NULL-byte followed by VARCHAR(10).
7243 // Put the NULL-byte
7244 res.append("\0", 1);
7245 // Then, add a valid VARCHAR(12) value.
7246 res.append("\xC", 1);
7247 res.append("123456789ab", 12);
7248
7249 on_disk_rec->Reset();
7250 on_disk_rec->PinSelf(rocksdb::Slice(res));
7251 }
7252
7253 1 void dbug_create_err_inplace_alter() {
7254 1 my_printf_error(ER_UNKNOWN_ERROR,
7255 "Intentional failure in inplace alter occurred.", MYF(0));
7256 1 }
7257 #endif // !defined(NDEBUG)
7258
7259 16319473 int ha_rocksdb::convert_record_from_storage_format(
7260 const rocksdb::Slice *const key, uchar *const buf) {
7261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16319473 times.
16319473 DBUG_EXECUTE_IF("myrocks_simulate_bad_row_read1",
7262 dbug_append_garbage_at_end(&m_retrieved_record););
7263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16319473 times.
16319473 DBUG_EXECUTE_IF("myrocks_simulate_bad_row_read2",
7264 dbug_truncate_record(&m_retrieved_record););
7265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16319473 times.
16319473 DBUG_EXECUTE_IF("myrocks_simulate_bad_row_read3",
7266 dbug_modify_rec_varchar12(&m_retrieved_record););
7267
7268 16319473 return convert_record_from_storage_format(key, &m_retrieved_record, buf);
7269 }
7270
7271 /*
7272 @brief
7273 Unpack the record in this->m_retrieved_record and this->m_last_rowkey from
7274 storage format into buf (which can be table->record[0] or table->record[1]).
7275
7276 @param key Table record's key in mem-comparable form.
7277 @param buf Store record in table->record[0] format here
7278
7279 @detail
7280 If the table has blobs, the unpacked data in buf may keep pointers to the
7281 data in this->m_retrieved_record.
7282
7283 The key is only needed to check its checksum value (the checksum is in
7284 m_retrieved_record).
7285
7286 @seealso
7287 rdb_converter::setup_read_decoders() Sets up data structures which tell
7288 which columns to decode.
7289
7290 @return
7291 0 OK
7292 other Error inpacking the data
7293 */
7294
7295 87773578 int ha_rocksdb::convert_record_from_storage_format(
7296 const rocksdb::Slice *const key, const rocksdb::Slice *const value,
7297 uchar *const buf) {
7298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 87773578 times.
87773578 assert(key != nullptr);
7299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 87773578 times.
87773578 assert(buf != nullptr);
7300
7301 87773578 return m_converter->decode(m_pk_descr, buf, key, value);
7302 }
7303
7304 24478 int ha_rocksdb::alloc_key_buffers(const TABLE *const table_arg,
7305 const Rdb_tbl_def *const tbl_def_arg) {
7306
1/2
✓ Branch 0 taken 24478 times.
✗ Branch 1 not taken.
24478 DBUG_ENTER_FUNC();
7307
7308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24478 times.
24478 assert(tbl_def_arg != nullptr);
7309
7310 24478 std::shared_ptr<Rdb_key_def> *const kd_arr = tbl_def_arg->m_key_descr_arr;
7311
7312 24478 uint max_packed_sk_len = 0;
7313 24478 uint pack_key_len = 0;
7314
7315
1/2
✓ Branch 0 taken 24478 times.
✗ Branch 1 not taken.
24478 m_pk_descr = kd_arr[pk_index(table_arg, tbl_def_arg)];
7316
7317 // move this into get_table_handler() ??
7318
1/2
✓ Branch 0 taken 24477 times.
✗ Branch 1 not taken.
24477 m_pk_descr->setup(table_arg, tbl_def_arg);
7319
7320 24477 pack_key_len = m_pk_descr->max_storage_fmt_length();
7321 #ifdef HAVE_PSI_INTERFACE
7322 24478 m_pk_packed_tuple = static_cast<uchar *>(
7323
1/2
✓ Branch 0 taken 24478 times.
✗ Branch 1 not taken.
24478 my_malloc(rdb_handler_memory_key, pack_key_len, MYF(0)));
7324 #else
7325 m_pk_packed_tuple = static_cast<uchar *>(
7326 my_malloc(PSI_NOT_INSTRUMENTED, pack_key_len, MYF(0)));
7327 #endif
7328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24478 times.
24478 if (m_pk_packed_tuple == nullptr) {
7329 goto error;
7330 }
7331
7332 /* Sometimes, we may use m_sk_packed_tuple for storing packed PK */
7333 24478 max_packed_sk_len = pack_key_len;
7334
2/2
✓ Branch 0 taken 34670 times.
✓ Branch 1 taken 24477 times.
59147 for (uint i = 0; i < table_arg->s->keys; i++) {
7335 /* Primary key was processed above */
7336
2/2
✓ Branch 0 taken 13670 times.
✓ Branch 1 taken 21000 times.
34670 if (i == table_arg->s->primary_key) continue;
7337
7338 // TODO: move this into get_table_handler() ??
7339
1/2
✓ Branch 0 taken 21000 times.
✗ Branch 1 not taken.
21000 kd_arr[i]->setup(table_arg, tbl_def_arg);
7340
7341 21000 const uint packed_len = kd_arr[i]->max_storage_fmt_length();
7342
2/2
✓ Branch 0 taken 11578 times.
✓ Branch 1 taken 9421 times.
20999 if (packed_len > max_packed_sk_len) {
7343 11578 max_packed_sk_len = packed_len;
7344 }
7345 }
7346
7347 #ifdef HAVE_PSI_INTERFACE
7348 48956 if (!(m_sk_packed_tuple = static_cast<uchar *>(
7349
1/2
✓ Branch 0 taken 24478 times.
✗ Branch 1 not taken.
24477 my_malloc(rdb_handler_memory_key, max_packed_sk_len, MYF(0)))) ||
7350 24478 !(m_sk_packed_tuple_old = static_cast<uchar *>(
7351
2/4
✓ Branch 0 taken 24478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24478 times.
✗ Branch 3 not taken.
24478 my_malloc(rdb_handler_memory_key, max_packed_sk_len, MYF(0)))) ||
7352 24477 !(m_end_key_packed_tuple = static_cast<uchar *>(
7353
4/8
✓ Branch 0 taken 24478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24477 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24477 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 24478 times.
73434 my_malloc(rdb_handler_memory_key, max_packed_sk_len, MYF(0)))) ||
7354 24478 !(m_pack_buffer = static_cast<uchar *>(
7355
2/4
✓ Branch 0 taken 24478 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24478 times.
24477 my_malloc(rdb_handler_memory_key, max_packed_sk_len, MYF(0))))) {
7356 #else
7357 if (!(m_sk_packed_tuple = static_cast<uchar *>(
7358 my_malloc(PSI_NOT_INSTRUMENTED, max_packed_sk_len, MYF(0)))) ||
7359 !(m_sk_packed_tuple_old = static_cast<uchar *>(
7360 my_malloc(PSI_NOT_INSTRUMENTED, max_packed_sk_len, MYF(0)))) ||
7361 !(m_end_key_packed_tuple = static_cast<uchar *>(
7362 my_malloc(PSI_NOT_INSTRUMENTED, max_packed_sk_len, MYF(0)))) ||
7363 !(m_pack_buffer = static_cast<uchar *>(
7364 my_malloc(PSI_NOT_INSTRUMENTED, max_packed_sk_len, MYF(0))))) {
7365 #endif
7366 goto error;
7367 }
7368
7369
1/2
✓ Branch 0 taken 24478 times.
✗ Branch 1 not taken.
24478 DBUG_RETURN(HA_EXIT_SUCCESS);
7370
7371 error:
7372 // If we're here then this means that at some point above an allocation may
7373 // have failed. To avoid any resource leaks and maintain a clear contract
7374 // we'll clean up before returning the error code.
7375 free_key_buffers();
7376
7377 DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
7378 }
7379
7380 48483 void ha_rocksdb::free_key_buffers() {
7381 48483 my_free(m_pk_packed_tuple);
7382 48484 m_pk_packed_tuple = nullptr;
7383
7384 48484 my_free(m_sk_packed_tuple);
7385 48484 m_sk_packed_tuple = nullptr;
7386
7387 48484 my_free(m_sk_packed_tuple_old);
7388 48485 m_sk_packed_tuple_old = nullptr;
7389
7390 48485 my_free(m_end_key_packed_tuple);
7391 48485 m_end_key_packed_tuple = nullptr;
7392
7393 48485 my_free(m_pack_buffer);
7394 48485 m_pack_buffer = nullptr;
7395
7396 48485 release_blob_buffer();
7397 48484 }
7398
7399 /**
7400 @return
7401 HA_EXIT_SUCCESS OK
7402 other HA_ERR error code (can be SE-specific)
7403 */
7404 24015 int ha_rocksdb::open(const char *const name, int mode, uint test_if_locked,
7405 const dd::Table *table_def MY_ATTRIBUTE((__unused__))) {
7406
1/2
✓ Branch 0 taken 24016 times.
✗ Branch 1 not taken.
24015 DBUG_ENTER_FUNC();
7407
7408
1/2
✓ Branch 0 taken 24016 times.
✗ Branch 1 not taken.
24016 int err = close();
7409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24016 times.
24016 if (err) {
7410 DBUG_RETURN(err);
7411 }
7412
7413
1/2
✓ Branch 0 taken 24016 times.
✗ Branch 1 not taken.
24016 m_table_handler = rdb_open_tables.get_table_handler(name);
7414
7415
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24016 times.
24016 if (m_table_handler == nullptr) {
7416 DBUG_RETURN(HA_ERR_OUT_OF_MEM);
7417 }
7418
7419
1/2
✓ Branch 0 taken 24016 times.
✗ Branch 1 not taken.
24016 my_core::thr_lock_data_init(&m_table_handler->m_thr_lock, &m_db_lock,
7420 nullptr);
7421 24016 m_io_perf.init(&m_table_handler->m_table_perf_context,
7422 24016 &m_table_handler->m_io_perf_read, &stats);
7423
7424 Rdb_perf_context_guard guard(&m_io_perf,
7425
3/6
✓ Branch 0 taken 24016 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24016 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24016 times.
✗ Branch 5 not taken.
24016 rocksdb_perf_context_level(ha_thd()));
7426
7427 24016 std::string fullname;
7428
2/4
✓ Branch 0 taken 24016 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24016 times.
✗ Branch 3 not taken.
24016 err = rdb_normalize_tablename(name, &fullname);
7429
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24016 times.
24016 if (err != HA_EXIT_SUCCESS) {
7430 rdb_open_tables.release_table_handler(m_table_handler);
7431 DBUG_RETURN(err);
7432 }
7433
7434
1/2
✓ Branch 0 taken 24016 times.
✗ Branch 1 not taken.
24016 m_tbl_def = ddl_manager.find(fullname);
7435
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 24010 times.
24016 if (m_tbl_def == nullptr) {
7436
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 rdb_open_tables.release_table_handler(m_table_handler);
7437
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 my_error(ER_INTERNAL_ERROR, MYF(0),
7438 "Attempt to open a table that is not present in RocksDB-SE data "
7439 "dictionary");
7440
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_RETURN(HA_ERR_ROCKSDB_INVALID_TABLE);
7441 }
7442
7443 24010 m_lock_rows = RDB_LOCK_NONE;
7444 24010 m_locked_row_action = THR_WAIT;
7445 24010 m_key_descr_arr = m_tbl_def->m_key_descr_arr;
7446
7447 /*
7448 Full table scan actually uses primary key
7449 (UPDATE needs to know this, otherwise it will go into infinite loop on
7450 queries like "UPDATE tbl SET pk=pk+100")
7451 */
7452 24010 key_used_on_scan = table->s->primary_key;
7453
7454 // close() above has already called free_key_buffers(). No need to do it here.
7455
1/2
✓ Branch 0 taken 24010 times.
✗ Branch 1 not taken.
24010 err = alloc_key_buffers(table, m_tbl_def);
7456
7457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24010 times.
24010 if (err) {
7458 rdb_open_tables.release_table_handler(m_table_handler);
7459 DBUG_RETURN(err);
7460 }
7461
7462 /*
7463 init_with_fields() is used to initialize table flags based on the field
7464 definitions in table->field[].
7465 It is called by open_binary_frm(), but that function calls the method for
7466 a temporary ha_rocksdb object which is later destroyed.
7467
7468 If we are here in ::open(), then init_with_fields() has not been called
7469 for this object. Call it ourselves, we want all member variables to be
7470 properly initialized.
7471 */
7472
1/2
✓ Branch 0 taken 24010 times.
✗ Branch 1 not taken.
24010 init_with_fields();
7473
7474 /* Initialize decoder */
7475
3/6
✓ Branch 0 taken 24010 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24010 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24008 times.
✗ Branch 5 not taken.
24010 m_converter.reset(new Rdb_converter(ha_thd(), m_tbl_def, table));
7476
7477 /*
7478 Update m_ttl_bytes address to same as Rdb_converter's m_ttl_bytes.
7479 Remove this code after moving convert_record_to_storage_format() into
7480 Rdb_converter class.
7481 */
7482 24007 m_ttl_bytes = m_converter->get_ttl_bytes_buffer();
7483
7484
1/2
✓ Branch 0 taken 24009 times.
✗ Branch 1 not taken.
24005 info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
7485
7486 /*
7487 The following load_XXX code calls row decode functions, and they do
7488 that without having done ::external_lock() or index_init()/rnd_init().
7489 (Note: this also means we're doing a read when there was no
7490 rdb_converter::setup_field_encoders() call)
7491
7492 Initialize the necessary variables for them:
7493 */
7494
7495 /* Load auto_increment value only once on first use. */
7496
6/6
✓ Branch 0 taken 4642 times.
✓ Branch 1 taken 19367 times.
✓ Branch 2 taken 2068 times.
✓ Branch 3 taken 2575 times.
✓ Branch 4 taken 2068 times.
✓ Branch 5 taken 21942 times.
24009 if (table->found_next_number_field && m_tbl_def->m_auto_incr_val == 0) {
7497
1/2
✓ Branch 0 taken 2068 times.
✗ Branch 1 not taken.
2068 load_auto_incr_value();
7498 }
7499
7500 /* Load hidden pk only once on first use. */
7501
6/8
✓ Branch 0 taken 24010 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10637 times.
✓ Branch 3 taken 13373 times.
✓ Branch 4 taken 84 times.
✓ Branch 5 taken 10553 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 24010 times.
24094 if (has_hidden_pk(table) && m_tbl_def->m_hidden_pk_val == 0 &&
7502
2/4
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
84 (err = load_hidden_pk_value()) != HA_EXIT_SUCCESS) {
7503 rdb_open_tables.release_table_handler(m_table_handler);
7504 free_key_buffers();
7505 DBUG_RETURN(err);
7506 }
7507
7508 /* Index block size in MyRocks: used by MySQL in query optimization */
7509 24010 stats.block_size = rocksdb_tbl_options->block_size;
7510
7511
1/2
✓ Branch 0 taken 24010 times.
✗ Branch 1 not taken.
24010 DBUG_RETURN(HA_EXIT_SUCCESS);
7512 24016 }
7513
7514 48000 int ha_rocksdb::close(void) {
7515
1/2
✓ Branch 0 taken 48002 times.
✗ Branch 1 not taken.
48000 DBUG_ENTER_FUNC();
7516
7517 48002 m_pk_descr = nullptr;
7518 48002 m_key_descr_arr = nullptr;
7519 48002 m_converter = nullptr;
7520 48002 m_iterator = nullptr;
7521
1/2
✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
48002 free_key_buffers();
7522
7523
2/2
✓ Branch 0 taken 23961 times.
✓ Branch 1 taken 24040 times.
48001 if (m_table_handler != nullptr) {
7524
1/2
✓ Branch 0 taken 23962 times.
✗ Branch 1 not taken.
23961 rdb_open_tables.release_table_handler(m_table_handler);
7525 23962 m_table_handler = nullptr;
7526 }
7527
7528 // These are needed to suppress valgrind errors in rocksdb.partition
7529
1/2
✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
48002 m_last_rowkey.mem_free();
7530 48001 m_sk_tails.free();
7531 48002 m_sk_tails_old.free();
7532 48002 m_pk_unpack_info.free();
7533
7534
1/2
✓ Branch 0 taken 48002 times.
✗ Branch 1 not taken.
48002 DBUG_RETURN(HA_EXIT_SUCCESS);
7535 }
7536
7537 static const char *rdb_error_messages[] = {
7538 "Table must have a PRIMARY KEY.",
7539 "Specifying DATA DIRECTORY for an individual table is not supported.",
7540 "Specifying INDEX DIRECTORY for an individual table is not supported.",
7541 "RocksDB commit failed.",
7542 "Failure during bulk load operation.",
7543 "Found data corruption.",
7544 "CRC checksum mismatch.",
7545 "Invalid table.",
7546 "Could not access RocksDB properties.",
7547 "File I/O error during merge/sort operation.",
7548 "RocksDB status: not found.",
7549 "RocksDB status: corruption.",
7550 "RocksDB status: not supported.",
7551 "RocksDB status: invalid argument.",
7552 "RocksDB status: io error.",
7553 "RocksDB status: no space.",
7554 "RocksDB status: merge in progress.",
7555 "RocksDB status: incomplete.",
7556 "RocksDB status: shutdown in progress.",
7557 "RocksDB status: timed out.",
7558 "RocksDB status: aborted.",
7559 "RocksDB status: lock limit reached.",
7560 "RocksDB status: busy.",
7561 "RocksDB status: deadlock.",
7562 "RocksDB status: expired.",
7563 "RocksDB status: try again.",
7564 };
7565
7566 static_assert((sizeof(rdb_error_messages) / sizeof(rdb_error_messages[0])) ==
7567 ((HA_ERR_ROCKSDB_LAST - HA_ERR_ROCKSDB_FIRST) + 1),
7568 "Number of error messages doesn't match number of error codes");
7569
7570 330 static const char *rdb_get_error_messages(int error) {
7571
4/4
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 247 times.
✓ Branch 2 taken 80 times.
✓ Branch 3 taken 3 times.
330 if (error >= HA_ERR_ROCKSDB_FIRST && error <= HA_ERR_ROCKSDB_LAST) {
7572 80 return rdb_error_messages[error - HA_ERR_ROCKSDB_FIRST];
7573 }
7574 250 return "";
7575 }
7576
7577 330 bool ha_rocksdb::get_error_message(const int error, String *const buf) {
7578
1/2
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
330 DBUG_ENTER_FUNC();
7579
7580 static_assert(HA_ERR_ROCKSDB_LAST > HA_ERR_FIRST,
7581 "HA_ERR_ROCKSDB_LAST > HA_ERR_FIRST");
7582 static_assert(HA_ERR_ROCKSDB_LAST > HA_ERR_LAST,
7583 "HA_ERR_ROCKSDB_LAST > HA_ERR_LAST");
7584
7585
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 330 times.
330 assert(buf != nullptr);
7586
7587
1/2
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
330 buf->append(rdb_get_error_messages(error));
7588
7589 // We can be called with the values which are < HA_ERR_FIRST because most
7590 // MySQL internal functions will just return HA_EXIT_FAILURE in case of
7591 // an error.
7592
7593
1/2
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
330 DBUG_RETURN(false);
7594 }
7595
7596 /*
7597 Generalized way to convert RocksDB status errors into MySQL error code, and
7598 print error message.
7599
7600 Each error code below maps to a RocksDB status code found in:
7601 rocksdb/include/rocksdb/status.h
7602 */
7603 24 int ha_rocksdb::rdb_error_to_mysql(const rocksdb::Status &s,
7604 const char *opt_msg) {
7605
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
24 assert(!s.ok());
7606
7607 int err;
7608
5/17
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 19 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
24 switch (s.code()) {
7609 case rocksdb::Status::Code::kOk:
7610 err = HA_EXIT_SUCCESS;
7611 break;
7612 case rocksdb::Status::Code::kNotFound:
7613 err = HA_ERR_ROCKSDB_STATUS_NOT_FOUND;
7614 break;
7615 case rocksdb::Status::Code::kCorruption:
7616 err = HA_ERR_ROCKSDB_STATUS_CORRUPTION;
7617 break;
7618 case rocksdb::Status::Code::kNotSupported:
7619 err = HA_ERR_ROCKSDB_STATUS_NOT_SUPPORTED;
7620 break;
7621 case rocksdb::Status::Code::kInvalidArgument:
7622 err = HA_ERR_ROCKSDB_STATUS_INVALID_ARGUMENT;
7623 break;
7624 1 case rocksdb::Status::Code::kIOError:
7625
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 err = (s.IsNoSpace()) ? HA_ERR_ROCKSDB_STATUS_NO_SPACE
7626 : HA_ERR_ROCKSDB_STATUS_IO_ERROR;
7627 1 break;
7628 case rocksdb::Status::Code::kMergeInProgress:
7629 err = HA_ERR_ROCKSDB_STATUS_MERGE_IN_PROGRESS;
7630 break;
7631 3 case rocksdb::Status::Code::kIncomplete:
7632 3 err = HA_ERR_ROCKSDB_STATUS_INCOMPLETE;
7633 3 break;
7634 case rocksdb::Status::Code::kShutdownInProgress:
7635 err = HA_ERR_ROCKSDB_STATUS_SHUTDOWN_IN_PROGRESS;
7636 break;
7637 case rocksdb::Status::Code::kTimedOut:
7638 err = HA_ERR_ROCKSDB_STATUS_TIMED_OUT;
7639 break;
7640 19 case rocksdb::Status::Code::kAborted:
7641
3/4
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 2 times.
19 err = (s.IsLockLimit()) ? HA_ERR_ROCKSDB_STATUS_LOCK_LIMIT
7642 : HA_ERR_ROCKSDB_STATUS_ABORTED;
7643 19 break;
7644 1 case rocksdb::Status::Code::kBusy:
7645
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 err = (s.IsDeadlock()) ? HA_ERR_ROCKSDB_STATUS_DEADLOCK
7646 : HA_ERR_ROCKSDB_STATUS_BUSY;
7647 1 break;
7648 case rocksdb::Status::Code::kExpired:
7649 err = HA_ERR_ROCKSDB_STATUS_EXPIRED;
7650 break;
7651 case rocksdb::Status::Code::kTryAgain:
7652 err = HA_ERR_ROCKSDB_STATUS_TRY_AGAIN;
7653 break;
7654 default:
7655 assert(0);
7656 return -1;
7657 }
7658
7659 24 std::string errMsg;
7660
3/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 7 times.
24 if (s.IsLockLimit()) {
7661 errMsg =
7662 "Operation aborted: Failed to acquire lock due to "
7663
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 "rocksdb_max_row_locks limit";
7664 } else {
7665
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 errMsg = s.ToString();
7666 }
7667
7668
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (opt_msg) {
7669 std::string concatenated_error = errMsg + " (" + std::string(opt_msg) + ")";
7670 my_error(ER_GET_ERRMSG, MYF(0), s.code(), concatenated_error.c_str(),
7671 rocksdb_hton_name);
7672 } else {
7673
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
24 my_error(ER_GET_ERRMSG, MYF(0), s.code(), errMsg.c_str(),
7674 rocksdb_hton_name);
7675 }
7676
7677 24 return err;
7678 }
7679
7680 /*
7681 Create structures needed for storing data in rocksdb. This is called when the
7682 table is created. The structures will be shared by all TABLE* objects.
7683
7684 @param
7685 table_arg Table with definition
7686 db_table "dbname.tablename"
7687 len strlen of the above
7688 actual_user_table_name actual table name in case of alter
7689 table copy algorithm
7690 tbl_def_arg tbl_def whose key_descr is being created/populated
7691 old_tbl_def_arg tbl_def from which keys are being copied over from
7692 (for use during inplace alter)
7693
7694 @return
7695 0 - Ok
7696 other - error, either given table ddl is not supported by rocksdb or OOM.
7697 */
7698 15319 int ha_rocksdb::create_key_defs(
7699 const TABLE *const table_arg, Rdb_tbl_def *const tbl_def_arg,
7700 const std::string &actual_user_table_name,
7701 const TABLE *const old_table_arg /* = nullptr */,
7702 const Rdb_tbl_def *const old_tbl_def_arg
7703 /* = nullptr */) const {
7704
1/2
✓ Branch 0 taken 15319 times.
✗ Branch 1 not taken.
15319 DBUG_ENTER_FUNC();
7705
7706
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15319 times.
15319 assert(table_arg != nullptr);
7707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15319 times.
15319 assert(table_arg->s != nullptr);
7708
7709
5/8
✓ Branch 0 taken 15319 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 15310 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
15319 DBUG_EXECUTE_IF("rocksdb_truncate_failure", {
7710 my_error(ER_INTERNAL_ERROR, MYF(0), "Simulated truncation failure.");
7711 DBUG_RETURN(HA_EXIT_FAILURE);
7712 });
7713
7714
4/6
✓ Branch 0 taken 15310 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 15307 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
15310 DBUG_EXECUTE_IF("rocksdb_truncate_failure_crash", DBUG_SUICIDE(););
7715
7716 /*
7717 These need to be one greater than MAX_INDEXES since the user can create
7718 MAX_INDEXES secondary keys and no primary key which would cause us
7719 to generate a hidden one.
7720 */
7721 15307 std::array<key_def_cf_info, MAX_INDEXES + 1> cfs;
7722
7723 /*
7724 NOTE: All new column families must be created before new index numbers are
7725 allocated to each key definition. See below for more details.
7726 http://github.com/MySQLOnRocksDB/mysql-5.6/issues/86#issuecomment-138515501
7727 */
7728
3/4
✓ Branch 0 taken 15307 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 15273 times.
15307 if (create_cfs(table_arg, tbl_def_arg, actual_user_table_name, &cfs)) {
7729
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 DBUG_RETURN(HA_EXIT_FAILURE);
7730 }
7731
7732 15273 uint64 ttl_duration = 0;
7733 15273 std::string ttl_column;
7734 uint ttl_field_offset;
7735
7736 uint err;
7737
3/4
✓ Branch 0 taken 15273 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 15249 times.
15273 if ((err = Rdb_key_def::extract_ttl_duration(table_arg, tbl_def_arg,
7738 &ttl_duration))) {
7739
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 DBUG_RETURN(err);
7740 }
7741
7742
3/4
✓ Branch 0 taken 15249 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 96 times.
✓ Branch 3 taken 15153 times.
15249 if ((err = Rdb_key_def::extract_ttl_col(table_arg, tbl_def_arg, &ttl_column,
7743 &ttl_field_offset))) {
7744
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 DBUG_RETURN(err);
7745 }
7746
7747 /* We don't currently support TTL on tables with hidden primary keys. */
7748
7/8
✓ Branch 0 taken 963 times.
✓ Branch 1 taken 14190 times.
✓ Branch 2 taken 963 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 939 times.
✓ Branch 6 taken 24 times.
✓ Branch 7 taken 15129 times.
15153 if (ttl_duration > 0 && has_hidden_pk(table_arg)) {
7749
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 my_error(ER_RDB_TTL_UNSUPPORTED, MYF(0));
7750
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 DBUG_RETURN(HA_EXIT_FAILURE);
7751 }
7752
7753 /*
7754 If TTL duration is not specified but TTL column was specified, throw an
7755 error because TTL column requires duration.
7756 */
7757
4/6
✓ Branch 0 taken 14190 times.
✓ Branch 1 taken 939 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14190 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 15129 times.
15129 if (ttl_duration == 0 && !ttl_column.empty()) {
7758 my_error(ER_RDB_TTL_COL_FORMAT, MYF(0), ttl_column.c_str());
7759 DBUG_RETURN(HA_EXIT_FAILURE);
7760 }
7761
7762
2/2
✓ Branch 0 taken 14531 times.
✓ Branch 1 taken 598 times.
15129 if (!old_tbl_def_arg) {
7763 /*
7764 old_tbl_def doesn't exist. this means we are in the process of creating
7765 a new table.
7766
7767 Get the index numbers (this will update the next_index_number)
7768 and create Rdb_key_def structures.
7769 */
7770
2/2
✓ Branch 0 taken 26619 times.
✓ Branch 1 taken 14474 times.
41093 for (uint i = 0; i < tbl_def_arg->m_key_count; i++) {
7771
3/4
✓ Branch 0 taken 26619 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 26562 times.
26619 if (create_key_def(table_arg, i, tbl_def_arg, &m_key_descr_arr[i], cfs[i],
7772 ttl_duration, ttl_column)) {
7773
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 DBUG_RETURN(HA_EXIT_FAILURE);
7774 }
7775 }
7776 } else {
7777 /*
7778 old_tbl_def exists. This means we are creating a new tbl_def as part of
7779 in-place alter table. Copy over existing keys from the old_tbl_def and
7780 generate the necessary new key definitions if any.
7781 */
7782
3/4
✓ Branch 0 taken 598 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 589 times.
598 if (create_inplace_key_defs(table_arg, tbl_def_arg, old_table_arg,
7783 old_tbl_def_arg, cfs, ttl_duration,
7784 ttl_column)) {
7785
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 DBUG_RETURN(HA_EXIT_FAILURE);
7786 }
7787 }
7788
7789
1/2
✓ Branch 0 taken 15063 times.
✗ Branch 1 not taken.
15063 DBUG_RETURN(HA_EXIT_SUCCESS);
7790 15307 }
7791
7792 /*
7793 Checks index parameters and creates column families needed for storing data
7794 in rocksdb if necessary.
7795
7796 @param in
7797 table_arg Table with definition
7798 db_table Table name
7799 tbl_def_arg Table def structure being populated
7800 actual_user_table_name actual table name in case
7801 of alter table copy algorithm
7802 @param out
7803 cfs CF info for each key definition in 'key_info' order
7804
7805 @return
7806 0 - Ok
7807 other - error
7808 */
7809 15307 int ha_rocksdb::create_cfs(
7810 const TABLE *const table_arg, Rdb_tbl_def *const tbl_def_arg,
7811 const std::string &actual_user_table_name,
7812 std::array<struct key_def_cf_info, MAX_INDEXES + 1> *const cfs) const {
7813
1/2
✓ Branch 0 taken 15307 times.
✗ Branch 1 not taken.
15307 DBUG_ENTER_FUNC();
7814
7815
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15307 times.
15307 assert(table_arg != nullptr);
7816
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15307 times.
15307 assert(table_arg->s != nullptr);
7817
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15307 times.
15307 assert(tbl_def_arg != nullptr);
7818
7819 char tablename_sys[NAME_LEN + 1];
7820
1/2
✓ Branch 0 taken 15307 times.
✗ Branch 1 not taken.
15307 my_core::filename_to_tablename(tbl_def_arg->base_tablename().c_str(),
7821 tablename_sys, sizeof(tablename_sys));
7822
7823
1/2
✓ Branch 0 taken 15307 times.
✗ Branch 1 not taken.
15307 uint primary_key_index = pk_index(table_arg, tbl_def_arg);
7824 std::string table_with_enforced_collation =
7825
6/10
✓ Branch 0 taken 13924 times.
✓ Branch 1 taken 1383 times.
✓ Branch 2 taken 13924 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1383 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13924 times.
✓ Branch 7 taken 1383 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
15307 actual_user_table_name.empty() ? tablename_sys : actual_user_table_name;
7826 /*
7827 The first loop checks the index parameters and creates
7828 column families if necessary.
7829 */
7830
2/2
✓ Branch 0 taken 28329 times.
✓ Branch 1 taken 15273 times.
43602 for (uint i = 0; i < tbl_def_arg->m_key_count; i++) {
7831 28329 std::shared_ptr<rocksdb::ColumnFamilyHandle> cf_handle;
7832
7833 // Internal consistency check to make sure that data in TABLE and
7834 // Rdb_tbl_def structures matches. Either both are missing or both are
7835 // specified. Yes, this is critical enough to make it into SHIP_ASSERT.
7836
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 28329 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
28329 SHIP_ASSERT(!table_arg->part_info == tbl_def_arg->base_partition().empty());
7837
7838 // Generate the name for the column family to use.
7839 28329 bool per_part_match_found = false;
7840 std::string cf_name =
7841
1/2
✓ Branch 0 taken 28329 times.
✗ Branch 1 not taken.
28329 generate_cf_name(i, table_arg, tbl_def_arg, &per_part_match_found);
7842
7843 // Prevent create from using the system column family.
7844
6/6
✓ Branch 0 taken 28320 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 28314 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 28314 times.
56649 if (cf_name == DEFAULT_SYSTEM_CF_NAME ||
7845 28320 cf_name == DEFAULT_TMP_SYSTEM_CF_NAME) {
7846
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 my_error(ER_WRONG_ARGUMENTS, MYF(0),
7847 "column family not valid for storing index data.");
7848
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 DBUG_RETURN(HA_EXIT_FAILURE);
7849 }
7850
7851
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 28308 times.
28314 if (cf_name == DEFAULT_TMP_CF_NAME) {
7852
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 my_error(ER_WRONG_ARGUMENTS, MYF(0),
7853 "reserved column family for storing temporary table data.");
7854
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_RETURN(HA_EXIT_FAILURE);
7855 }
7856 // Populate cf_name for tmp tables.
7857
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 28212 times.
28308 if (is_tmp_table(tbl_def_arg->full_tablename())) {
7858
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 93 times.
96 if (!cf_name.empty()) {
7859
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 my_error(ER_WRONG_ARGUMENTS, MYF(0),
7860 "custom column family for temporary table is not allowed.");
7861
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(HA_EXIT_FAILURE);
7862 }
7863
1/2
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
93 cf_name = DEFAULT_TMP_CF_NAME;
7864 }
7865
7866
7/12
✓ Branch 0 taken 28305 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 28302 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
28305 DBUG_EXECUTE_IF("rocksdb_create_primary_cf", {
7867 if (cf_name == "cf_primary_key") {
7868 THD *const thd = my_core::thd_get_current_thd();
7869 static constexpr char act[] =
7870 "now signal ready_to_mark_cf_dropped_in_create_cfs "
7871 "wait_for mark_cf_dropped_done_in_create_cfs";
7872 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
7873 }
7874 });
7875
7876
8/12
✓ Branch 0 taken 28305 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 28299 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
28305 DBUG_EXECUTE_IF("rocksdb_create_secondary_cf", {
7877 if (cf_name == "cf_secondary_key") {
7878 THD *const thd = my_core::thd_get_current_thd();
7879 static constexpr char act[] =
7880 "now signal ready_to_mark_cf_dropped_in_create_cfs "
7881 "wait_for mark_cf_dropped_done_in_create_cfs";
7882 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
7883 }
7884 });
7885
7886 // if not specified, use default CF name
7887
2/2
✓ Branch 0 taken 26673 times.
✓ Branch 1 taken 1632 times.
28305 if (cf_name.empty()) {
7888
4/4
✓ Branch 0 taken 12242 times.
✓ Branch 1 taken 14431 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 12233 times.
26673 if (i != primary_key_index && rocksdb_use_default_sk_cf)
7889
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 cf_name = DEFAULT_SK_CF_NAME;
7890 else
7891
1/2
✓ Branch 0 taken 26664 times.
✗ Branch 1 not taken.
26664 cf_name = DEFAULT_CF_NAME;
7892 }
7893
7894 // Here's how `get_or_create_cf` will use the input parameters:
7895 //
7896 // `cf_name` - will be used as a CF name.
7897 {
7898 auto local_dict_manager =
7899
1/2
✓ Branch 0 taken 28305 times.
✗ Branch 1 not taken.
28305 dict_manager.get_dict_manager_selector_non_const(cf_name);
7900
1/2
✓ Branch 0 taken 28305 times.
✗ Branch 1 not taken.
28305 std::lock_guard<Rdb_dict_manager> dm_lock(*local_dict_manager);
7901 28305 cf_handle = cf_manager.get_or_create_cf(rdb, cf_name,
7902
1/2
✓ Branch 0 taken 28305 times.
✗ Branch 1 not taken.
28305 !rocksdb_no_create_column_family);
7903
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 28301 times.
28305 if (!cf_handle) {
7904
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 DBUG_RETURN(HA_EXIT_FAILURE);
7905 }
7906
7907
1/2
✓ Branch 0 taken 28301 times.
✗ Branch 1 not taken.
28301 uint32 cf_id = cf_handle->GetID();
7908
7909 // If the cf is marked as dropped, we fail it here.
7910 // The cf can be dropped after this point, we will
7911 // check again when committing metadata changes.
7912
3/4
✓ Branch 0 taken 28301 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 28295 times.
28301 if (local_dict_manager->get_dropped_cf(cf_id)) {
7913
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 my_error(ER_CF_DROPPED, MYF(0), cf_name.c_str());
7914
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_RETURN(HA_EXIT_FAILURE);
7915 }
7916
7917 84885 if (cf_manager.create_cf_flags_if_needed(local_dict_manager,
7918
3/6
✓ Branch 0 taken 28295 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28295 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 28295 times.
28295 cf_handle->GetID(), cf_name,
7919 per_part_match_found)) {
7920 DBUG_RETURN(HA_EXIT_FAILURE);
7921 }
7922
2/2
✓ Branch 0 taken 28295 times.
✓ Branch 1 taken 10 times.
28305 }
7923
7924 // The CF can be dropped from cf_manager at this point. This is part of
7925 // create table or alter table. If the drop happens before metadata are
7926 // written, create table or alter table will fail.
7927 28295 auto &cf = (*cfs)[i];
7928
7929 28295 cf.cf_handle = cf_handle;
7930
1/2
✓ Branch 0 taken 28295 times.
✗ Branch 1 not taken.
28295 cf.is_reverse_cf = Rdb_cf_manager::is_cf_name_reverse(cf_name.c_str());
7931 28295 cf.is_per_partition_cf = per_part_match_found;
7932
4/4
✓ Branch 0 taken 28295 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 28295 times.
✓ Branch 3 taken 34 times.
28363 }
7933
7934
1/2
✓ Branch 0 taken 15273 times.
✗ Branch 1 not taken.
15273 DBUG_RETURN(HA_EXIT_SUCCESS);
7935 15307 }
7936
7937 /*
7938 Create key definition needed for storing data in rocksdb during ADD index
7939 inplace operations.
7940
7941 @param in
7942 table_arg Table with definition
7943 tbl_def_arg New table def structure being populated
7944 old_tbl_def_arg Old(current) table def structure
7945 cfs Struct array which contains column family information
7946
7947 @return
7948 0 - Ok
7949 other - error, either given table ddl is not supported by rocksdb or OOM.
7950 */
7951 598 int ha_rocksdb::create_inplace_key_defs(
7952 const TABLE *const table_arg, Rdb_tbl_def *const tbl_def_arg,
7953 const TABLE *const old_table_arg, const Rdb_tbl_def *const old_tbl_def_arg,
7954 const std::array<key_def_cf_info, MAX_INDEXES + 1> &cfs,
7955 uint64 ttl_duration, const std::string &ttl_column) const {
7956
1/2
✓ Branch 0 taken 598 times.
✗ Branch 1 not taken.
598 DBUG_ENTER_FUNC();
7957
7958
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 598 times.
598 assert(table_arg != nullptr);
7959
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 598 times.
598 assert(tbl_def_arg != nullptr);
7960
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 598 times.
598 assert(old_tbl_def_arg != nullptr);
7961
7962 598 std::shared_ptr<Rdb_key_def> *const old_key_descr =
7963 old_tbl_def_arg->m_key_descr_arr;
7964 598 std::shared_ptr<Rdb_key_def> *const new_key_descr =
7965 tbl_def_arg->m_key_descr_arr;
7966 const std::unordered_map<std::string, uint> old_key_pos =
7967 get_old_key_positions(table_arg, tbl_def_arg, old_table_arg,
7968
1/2
✓ Branch 0 taken 598 times.
✗ Branch 1 not taken.
598 old_tbl_def_arg);
7969
7970 uint i;
7971
2/2
✓ Branch 0 taken 1429 times.
✓ Branch 1 taken 589 times.
2018 for (i = 0; i < tbl_def_arg->m_key_count; i++) {
7972
3/6
✓ Branch 0 taken 1429 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1429 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1429 times.
✗ Branch 5 not taken.
1429 const auto &it = old_key_pos.find(get_key_name(i, table_arg, tbl_def_arg));
7973
7974
2/2
✓ Branch 0 taken 954 times.
✓ Branch 1 taken 475 times.
1429 if (it != old_key_pos.end()) {
7975 /*
7976 Found matching index in old table definition, so copy it over to the
7977 new one created.
7978 */
7979 954 const Rdb_key_def &okd = *old_key_descr[it->second];
7980
7981
1/2
✓ Branch 0 taken 954 times.
✗ Branch 1 not taken.
954 const GL_INDEX_ID gl_index_id = okd.get_gl_index_id();
7982 954 struct Rdb_index_info index_info;
7983 1908 if (!dict_manager.get_dict_manager_selector_const(gl_index_id.cf_id)
7984
3/6
✓ Branch 0 taken 954 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 954 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 954 times.
954 ->get_index_info(gl_index_id, &index_info)) {
7985 LogPluginErrMsg(ERROR_LEVEL, 0,
7986 "Could not get index information for Index Number "
7987 "(%u,%u), table %s",
7988 gl_index_id.cf_id, gl_index_id.index_id,
7989 old_tbl_def_arg->full_tablename().c_str());
7990 DBUG_RETURN(HA_EXIT_FAILURE);
7991 }
7992
7993 uint32 ttl_rec_offset =
7994
1/2
✓ Branch 0 taken 954 times.
✗ Branch 1 not taken.
954 Rdb_key_def::has_index_flag(index_info.m_index_flags,
7995 Rdb_key_def::TTL_FLAG)
7996
3/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 915 times.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
954 ? Rdb_key_def::calculate_index_flag_offset(
7997 index_info.m_index_flags, Rdb_key_def::TTL_FLAG)
7998 954 : UINT_MAX;
7999
8000 /*
8001 We can't use the copy constructor because we need to update the
8002 keynr within the pack_info for each field and the keyno of the keydef
8003 itself.
8004 */
8005 954 new_key_descr[i] = std::make_shared<Rdb_key_def>(
8006
1/2
✓ Branch 0 taken 954 times.
✗ Branch 1 not taken.
1908 okd.get_index_number(), i, okd.get_shared_cf(),
8007 index_info.m_index_dict_version, index_info.m_index_type,
8008 954 index_info.m_kv_version, okd.m_is_reverse_cf,
8009 954 okd.m_is_per_partition_cf, okd.m_name.c_str(),
8010 954 dict_manager.get_dict_manager_selector_const(gl_index_id.cf_id)
8011
2/4
✓ Branch 0 taken 954 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 954 times.
✗ Branch 3 not taken.
1908 ->get_stats(gl_index_id),
8012 954 index_info.m_index_flags, ttl_rec_offset, index_info.m_ttl_duration);
8013
3/4
✓ Branch 0 taken 475 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 466 times.
475 } else if (create_key_def(table_arg, i, tbl_def_arg, &new_key_descr[i],
8014 475 cfs[i], ttl_duration, ttl_column)) {
8015
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 DBUG_RETURN(HA_EXIT_FAILURE);
8016 }
8017
8018
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1420 times.
1420 assert(new_key_descr[i] != nullptr);
8019
1/2
✓ Branch 0 taken 1420 times.
✗ Branch 1 not taken.
1420 new_key_descr[i]->setup(table_arg, tbl_def_arg);
8020 }
8021
8022 589 tbl_def_arg->m_tbl_stats.set(new_key_descr[0]->m_stats.m_rows, 0, 0);
8023
8024
1/2
✓ Branch 0 taken 589 times.
✗ Branch 1 not taken.
589 DBUG_RETURN(HA_EXIT_SUCCESS);
8025 598 }
8026
8027 598 std::unordered_map<std::string, uint> ha_rocksdb::get_old_key_positions(
8028 const TABLE *const table_arg, const Rdb_tbl_def *const tbl_def_arg,
8029 const TABLE *const old_table_arg,
8030 const Rdb_tbl_def *const old_tbl_def_arg) const {
8031
1/2
✓ Branch 0 taken 598 times.
✗ Branch 1 not taken.
598 DBUG_ENTER_FUNC();
8032
8033
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 598 times.
598 assert(table_arg != nullptr);
8034
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 598 times.
598 assert(old_table_arg != nullptr);
8035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 598 times.
598 assert(tbl_def_arg != nullptr);
8036
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 598 times.
598 assert(old_tbl_def_arg != nullptr);
8037
8038 598 std::shared_ptr<Rdb_key_def> *const old_key_descr =
8039 old_tbl_def_arg->m_key_descr_arr;
8040 598 std::unordered_map<std::string, uint> old_key_pos;
8041 598 std::unordered_map<std::string, uint> new_key_pos;
8042 uint i;
8043
8044
2/2
✓ Branch 0 taken 1429 times.
✓ Branch 1 taken 598 times.
2027 for (i = 0; i < tbl_def_arg->m_key_count; i++) {
8045
3/6
✓ Branch 0 taken 1429 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1429 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1429 times.
✗ Branch 5 not taken.
1429 new_key_pos[get_key_name(i, table_arg, tbl_def_arg)] = i;
8046 }
8047
8048
2/2
✓ Branch 0 taken 1136 times.
✓ Branch 1 taken 598 times.
1734 for (i = 0; i < old_tbl_def_arg->m_key_count; i++) {
8049
3/4
✓ Branch 0 taken 1136 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
✓ Branch 3 taken 944 times.
1136 if (is_hidden_pk(i, old_table_arg, old_tbl_def_arg)) {
8050
1/2
✓ Branch 0 taken 192 times.
✗ Branch 1 not taken.
192 old_key_pos[old_key_descr[i]->m_name] = i;
8051 374 continue;
8052 }
8053
8054 /*
8055 In case of matching key name, need to check key parts of keys as well,
8056 in case a simultaneous drop + add is performed, where the key name is the
8057 same but the key parts are different.
8058
8059 Example:
8060 CREATE TABLE t1 (a INT, b INT, KEY ka(a)) ENGINE=RocksDB;
8061 ALTER TABLE t1 DROP INDEX ka, ADD INDEX ka(b), ALGORITHM=INPLACE;
8062 */
8063 944 const KEY *const old_key = &old_table_arg->key_info[i];
8064
2/4
✓ Branch 0 taken 944 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 944 times.
✗ Branch 3 not taken.
944 const auto &it = new_key_pos.find(old_key->name);
8065
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 774 times.
944 if (it == new_key_pos.end()) {
8066 170 continue;
8067 }
8068
8069 774 KEY *const new_key = &table_arg->key_info[it->second];
8070
8071 /*
8072 Check that the key is identical between old and new tables.
8073 If not, we still need to create a new index.
8074
8075 The exception is if there is an index changed from unique to non-unique,
8076 in these cases we don't need to rebuild as they are stored the same way in
8077 RocksDB.
8078 */
8079 774 bool unique_to_non_unique =
8080
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 768 times.
780 ((old_key->flags ^ new_key->flags) == HA_NOSAME) &&
8081
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 (old_key->flags & HA_NOSAME);
8082
8083
6/8
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 768 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 768 times.
774 if (compare_keys(old_key, new_key) && !unique_to_non_unique) {
8084 6 continue;
8085 }
8086
8087 /* Check to make sure key parts match. */
8088
3/4
✓ Branch 0 taken 768 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 762 times.
768 if (compare_key_parts(old_key, new_key)) {
8089 6 continue;
8090 }
8091
8092
2/4
✓ Branch 0 taken 762 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 762 times.
✗ Branch 3 not taken.
762 old_key_pos[old_key->name] = i;
8093 }
8094
8095
1/2
✓ Branch 0 taken 598 times.
✗ Branch 1 not taken.
1196 DBUG_RETURN(old_key_pos);
8096 598 }
8097
8098 /* Check to see if two keys are identical. */
8099 2145 int ha_rocksdb::compare_keys(const KEY *const old_key,
8100 const KEY *const new_key) const {
8101
1/2
✓ Branch 0 taken 2145 times.
✗ Branch 1 not taken.
2145 DBUG_ENTER_FUNC();
8102
8103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2145 times.
2145 assert(old_key != nullptr);
8104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2145 times.
2145 assert(new_key != nullptr);
8105
8106 /* Check index name. */
8107
2/2
✓ Branch 0 taken 723 times.
✓ Branch 1 taken 1422 times.
2145 if (strcmp(old_key->name, new_key->name) != 0) {
8108
1/2
✓ Branch 0 taken 723 times.
✗ Branch 1 not taken.
723 DBUG_RETURN(HA_EXIT_FAILURE);
8109 }
8110
8111 /* If index algorithms are different then keys are different. */
8112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1422 times.
1422 if (old_key->algorithm != new_key->algorithm) {
8113 DBUG_RETURN(HA_EXIT_FAILURE);
8114 }
8115
8116 /* Check that the key is identical between old and new tables. */
8117
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1416 times.
1422 if ((old_key->flags ^ new_key->flags) & HA_KEYFLAG_MASK) {
8118
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_RETURN(HA_EXIT_FAILURE);
8119 }
8120
8121 /* Check index comment. (for column family changes) */
8122
1/2
✓ Branch 0 taken 1416 times.
✗ Branch 1 not taken.
1416 std::string old_comment(old_key->comment.str, old_key->comment.length);
8123
1/2
✓ Branch 0 taken 1416 times.
✗ Branch 1 not taken.
1416 std::string new_comment(new_key->comment.str, new_key->comment.length);
8124
2/4
✓ Branch 0 taken 1416 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1416 times.
1416 if (old_comment.compare(new_comment) != 0) {
8125 DBUG_RETURN(HA_EXIT_FAILURE);
8126 }
8127
8128
1/2
✓ Branch 0 taken 1416 times.
✗ Branch 1 not taken.
1416 DBUG_RETURN(HA_EXIT_SUCCESS);
8129 1416 }
8130
8131 /* Check two keys to ensure that key parts within keys match */
8132 768 int ha_rocksdb::compare_key_parts(const KEY *const old_key,
8133 const KEY *const new_key) const {
8134
1/2
✓ Branch 0 taken 768 times.
✗ Branch 1 not taken.
768 DBUG_ENTER_FUNC();
8135
8136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 768 times.
768 assert(old_key != nullptr);
8137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 768 times.
768 assert(new_key != nullptr);
8138
8139 /* Skip if key parts do not match, as it is a different key */
8140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 768 times.
768 if (new_key->user_defined_key_parts != old_key->user_defined_key_parts) {
8141 DBUG_RETURN(HA_EXIT_FAILURE);
8142 }
8143
8144 /* Check to see that key parts themselves match */
8145
2/2
✓ Branch 0 taken 1117 times.
✓ Branch 1 taken 762 times.
1879 for (uint i = 0; i < old_key->user_defined_key_parts; i++) {
8146 1117 if (strcmp(old_key->key_part[i].field->field_name,
8147
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1114 times.
1117 new_key->key_part[i].field->field_name) != 0) {
8148
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(HA_EXIT_FAILURE);
8149 }
8150
8151 /* Check if prefix index key part length has changed */
8152
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1111 times.
1114 if (old_key->key_part[i].length != new_key->key_part[i].length) {
8153
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(HA_EXIT_FAILURE);
8154 }
8155 }
8156
8157
1/2
✓ Branch 0 taken 762 times.
✗ Branch 1 not taken.
762 DBUG_RETURN(HA_EXIT_SUCCESS);
8158 }
8159
8160 /*
8161 Create key definition needed for storing data in rocksdb.
8162 This can be called either during CREATE table or doing ADD index operations.
8163
8164 @param in
8165 table_arg Table with definition
8166 i Position of index being created inside table_arg->key_info
8167 tbl_def_arg Table def structure being populated
8168 cf_info Struct which contains column family information
8169
8170 @param out
8171 new_key_def Newly created index definition.
8172
8173 @return
8174 0 - Ok
8175 other - error, either given table ddl is not supported by rocksdb or OOM.
8176 */
8177 27094 int ha_rocksdb::create_key_def(const TABLE *const table_arg, const uint i,
8178 const Rdb_tbl_def *const tbl_def_arg,
8179 std::shared_ptr<Rdb_key_def> *const new_key_def,
8180 const struct key_def_cf_info &cf_info,
8181 uint64 ttl_duration,
8182 const std::string &ttl_column) const {
8183
1/2
✓ Branch 0 taken 27094 times.
✗ Branch 1 not taken.
27094 DBUG_ENTER_FUNC();
8184
8185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27094 times.
27094 assert(new_key_def != nullptr);
8186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27094 times.
27094 assert(*new_key_def == nullptr);
8187
8188 const uint index_id =
8189
2/4
✓ Branch 0 taken 27094 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27094 times.
✗ Branch 3 not taken.
27094 ddl_manager.get_and_update_next_number(cf_info.cf_handle->GetID());
8190 27094 const uint16_t index_dict_version = Rdb_key_def::INDEX_INFO_VERSION_LATEST;
8191 uchar index_type;
8192 uint16_t kv_version;
8193
8194
3/4
✓ Branch 0 taken 27094 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5920 times.
✓ Branch 3 taken 21174 times.
27094 if (is_hidden_pk(i, table_arg, tbl_def_arg)) {
8195 5920 index_type = Rdb_key_def::INDEX_TYPE_HIDDEN_PRIMARY;
8196 5920 kv_version = Rdb_key_def::PRIMARY_FORMAT_VERSION_LATEST;
8197
2/2
✓ Branch 0 taken 8605 times.
✓ Branch 1 taken 12569 times.
21174 } else if (i == table_arg->s->primary_key) {
8198 8605 index_type = Rdb_key_def::INDEX_TYPE_PRIMARY;
8199 8605 uint16 pk_latest_version = Rdb_key_def::PRIMARY_FORMAT_VERSION_LATEST;
8200 8605 kv_version = pk_latest_version;
8201 } else {
8202 12569 index_type = Rdb_key_def::INDEX_TYPE_SECONDARY;
8203 12569 uint16 sk_latest_version = Rdb_key_def::SECONDARY_FORMAT_VERSION_LATEST;
8204 12569 kv_version = sk_latest_version;
8205 }
8206
8207 // Use PRIMARY_FORMAT_VERSION_UPDATE1 here since it is the same value as
8208 // SECONDARY_FORMAT_VERSION_UPDATE1 so it doesn't matter if this is a
8209 // primary key or secondary key.
8210
3/4
✓ Branch 0 taken 27094 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 27088 times.
27094 DBUG_EXECUTE_IF("MYROCKS_LEGACY_VARBINARY_FORMAT", {
8211 kv_version = Rdb_key_def::PRIMARY_FORMAT_VERSION_UPDATE1;
8212 });
8213
8214
2/6
✓ Branch 0 taken 27094 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27094 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
27094 DBUG_EXECUTE_IF("MYROCKS_NO_COVERED_BITMAP_FORMAT", {
8215 if (index_type == Rdb_key_def::INDEX_TYPE_SECONDARY) {
8216 kv_version = Rdb_key_def::SECONDARY_FORMAT_VERSION_UPDATE2;
8217 }
8218 });
8219
8220
5/6
✓ Branch 0 taken 27094 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 27079 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 12 times.
27094 DBUG_EXECUTE_IF("MYROCKS_NO_LEAD_BYTE_VARCHAR_SPACE_PADDED", {
8221 if (index_type == Rdb_key_def::INDEX_TYPE_SECONDARY) {
8222 kv_version = Rdb_key_def::SECONDARY_FORMAT_VERSION_TTL;
8223 } else {
8224 kv_version = Rdb_key_def::PRIMARY_FORMAT_VERSION_TTL;
8225 }
8226 });
8227
8228
2/2
✓ Branch 0 taken 1317 times.
✓ Branch 1 taken 25777 times.
27094 uint32 index_flags = (ttl_duration > 0 ? Rdb_key_def::TTL_FLAG : 0);
8229
8230 uint32 ttl_rec_offset =
8231
1/2
✓ Branch 0 taken 27094 times.
✗ Branch 1 not taken.
27094 Rdb_key_def::has_index_flag(index_flags, Rdb_key_def::TTL_FLAG)
8232
3/4
✓ Branch 0 taken 1317 times.
✓ Branch 1 taken 25777 times.
✓ Branch 2 taken 1317 times.
✗ Branch 3 not taken.
27094 ? Rdb_key_def::calculate_index_flag_offset(index_flags,
8233 Rdb_key_def::TTL_FLAG)
8234 27094 : UINT_MAX;
8235
8236
1/2
✓ Branch 0 taken 27094 times.
✗ Branch 1 not taken.
27094 const char *const key_name = get_key_name(i, table_arg, m_tbl_def);
8237 27094 *new_key_def = std::make_shared<Rdb_key_def>(
8238 27094 index_id, i, cf_info.cf_handle, index_dict_version, index_type,
8239
1/2
✓ Branch 0 taken 27094 times.
✗ Branch 1 not taken.
27094 kv_version, cf_info.is_reverse_cf, cf_info.is_per_partition_cf, key_name,
8240
1/2
✓ Branch 0 taken 27094 times.
✗ Branch 1 not taken.
81282 Rdb_index_stats(), index_flags, ttl_rec_offset, ttl_duration);
8241
8242
2/2
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 26506 times.
27094 if (!ttl_column.empty()) {
8243
1/2
✓ Branch 0 taken 588 times.
✗ Branch 1 not taken.
588 (*new_key_def)->m_ttl_column = ttl_column;
8244 }
8245
8246
3/4
✓ Branch 0 taken 27094 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 27028 times.
27094 if ((*new_key_def)->extract_partial_index_info(table_arg, tbl_def_arg)) {
8247
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 DBUG_RETURN(HA_EXIT_FAILURE);
8248 }
8249
8250 // initialize key_def
8251
1/2
✓ Branch 0 taken 27028 times.
✗ Branch 1 not taken.
27028 (*new_key_def)->setup(table_arg, tbl_def_arg);
8252
1/2
✓ Branch 0 taken 27028 times.
✗ Branch 1 not taken.
27028 DBUG_RETURN(HA_EXIT_SUCCESS);
8253 }
8254
8255 10256 bool rdb_is_tablename_normalized(const std::string &tablename) {
8256
4/6
✓ Branch 0 taken 10256 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5018 times.
✓ Branch 3 taken 5238 times.
✓ Branch 4 taken 5018 times.
✗ Branch 5 not taken.
10256 return tablename.size() < 2 || (tablename[0] != '.' && tablename[1] != '/');
8257 }
8258
8259 56809 int rdb_normalize_tablename(const std::string &tablename,
8260 std::string *const strbuf) {
8261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56809 times.
56809 assert(strbuf != nullptr);
8262
8263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56809 times.
56809 if (tablename.size() < 2) {
8264 assert(0); // We were not passed table name?
8265 return HA_ERR_ROCKSDB_INVALID_TABLE;
8266 }
8267
8268 56809 size_t pos = tablename.find_last_of('/');
8269
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56810 times.
56810 if (pos == std::string::npos) {
8270 assert(0); // We were not passed table name?
8271 return HA_ERR_ROCKSDB_INVALID_TABLE;
8272 }
8273
8274
1/2
✓ Branch 0 taken 56810 times.
✗ Branch 1 not taken.
56810 std::string table_name = tablename.substr(pos + 1);
8275 56810 std::string schema_name;
8276 /*
8277 Special parsing for tmp tables.
8278 We will return TMP_SCHEMA_NAME for external/internal tmp tables by
8279 parsing the values passed to tablename from sql layer.
8280
8281 Below are different tablename for various cases:
8282 1) Create user table : tablename = "./<SCHEMA>/<TABLE>"
8283 2) Alter user table : tablename = "./<SCHEMA>/#sql_*"
8284 3) External tmp tables : tablename = "/<TMP_DIRECTORY_PATH>/#sql_*"
8285 4) Intrinsic tmp tables: tablename = "/<TMP_DIRECTORY_PATH>/#sql_*"
8286 */
8287
4/4
✓ Branch 0 taken 254 times.
✓ Branch 1 taken 56555 times.
✓ Branch 2 taken 245 times.
✓ Branch 3 taken 56565 times.
57065 if (strlen(opt_mysql_tmpdir) < tablename.length() &&
8288
2/2
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 9 times.
254 strncmp(opt_mysql_tmpdir, tablename.c_str(), strlen(opt_mysql_tmpdir)) ==
8289 0) {
8290
1/2
✓ Branch 0 taken 245 times.
✗ Branch 1 not taken.
245 schema_name = TMP_SCHEMA_NAME;
8291 } else {
8292
3/6
✓ Branch 0 taken 56564 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56564 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 56564 times.
56565 if (tablename[0] != '.' || tablename[1] != '/') {
8293 assert(0);
8294 return HA_ERR_ROCKSDB_INVALID_TABLE;
8295 }
8296
1/2
✓ Branch 0 taken 56564 times.
✗ Branch 1 not taken.
56564 schema_name = tablename.substr(2, pos - 2);
8297 }
8298
2/4
✓ Branch 0 taken 56809 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56809 times.
✗ Branch 3 not taken.
56809 *strbuf = schema_name + "." + table_name;
8299
8300 56810 return HA_EXIT_SUCCESS;
8301 56810 }
8302
8303 /*
8304 Check to see if the user's original statement includes foreign key
8305 references
8306 */
8307 14460 bool ha_rocksdb::contains_foreign_key(THD *const thd) {
8308 bool success;
8309
1/2
✓ Branch 0 taken 14460 times.
✗ Branch 1 not taken.
14460 const char *str = thd->query().str;
8310
8311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14460 times.
14460 assert(str != nullptr);
8312
8313
1/2
✓ Branch 0 taken 14472 times.
✗ Branch 1 not taken.
14472 while (*str != '\0') {
8314 // Scan from our current pos looking for 'FOREIGN'
8315
1/2
✓ Branch 0 taken 14472 times.
✗ Branch 1 not taken.
14472 str = rdb_find_in_string(str, "FOREIGN", &success);
8316
2/2
✓ Branch 0 taken 14442 times.
✓ Branch 1 taken 30 times.
14472 if (!success) {
8317 14442 return false;
8318 }
8319
8320 // Skip past the found "FOREIGN'
8321
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 str = rdb_check_next_token(&my_charset_bin, str, "FOREIGN", &success);
8322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 assert(success);
8323
8324
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 24 times.
30 if (!my_isspace(&my_charset_bin, *str)) {
8325 6 return false;
8326 }
8327
8328 // See if the next token is 'KEY'
8329
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 str = rdb_check_next_token(&my_charset_bin, str, "KEY", &success);
8330
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (!success) {
8331 12 continue;
8332 }
8333
8334 // See if the next token is '('
8335
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 str = rdb_check_next_token(&my_charset_bin, str, "(", &success);
8336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!success) {
8337 // There is an optional index id after 'FOREIGN KEY', skip it
8338 str = rdb_skip_id(&my_charset_bin, str);
8339
8340 // Now check for '(' again
8341 str = rdb_check_next_token(&my_charset_bin, str, "(", &success);
8342 }
8343
8344 // If we have found 'FOREIGN KEY [<word>] (' we can be confident we have
8345 // a foreign key clause.
8346 12 return success;
8347 }
8348
8349 // We never found a valid foreign key clause
8350 return false;
8351 }
8352
8353 /**
8354 @brief
8355 splits the normalized table name of <dbname>.<tablename>#P#<part_no> into
8356 the <dbname>, <tablename> and <part_no> components.
8357
8358 @param dbbuf returns database name/table_schema
8359 @param tablebuf returns tablename
8360 @param partitionbuf returns partition suffix if there is one
8361 @return HA_EXIT_SUCCESS on success, non-zero on failure to split
8362 */
8363 34204 int rdb_split_normalized_tablename(const std::string &fullname,
8364 std::string *const db,
8365 std::string *const table,
8366 std::string *const partition) {
8367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34204 times.
34204 assert(!fullname.empty());
8368
8369 #define RDB_PARTITION_STR "#P#"
8370
8371 /* Normalize returns dbname.tablename. */
8372 34204 size_t dotpos = fullname.find('.');
8373
8374 /* Invalid table name? */
8375
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34204 times.
34204 if (dotpos == std::string::npos) {
8376 return HA_ERR_ROCKSDB_INVALID_TABLE;
8377 }
8378
8379 // Table must have a database name associated with it.
8380
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34204 times.
34204 assert(dotpos > 0);
8381
8382
1/2
✓ Branch 0 taken 34204 times.
✗ Branch 1 not taken.
34204 if (db != nullptr) {
8383 34204 *db = fullname.substr(0, dotpos);
8384 }
8385
8386 34204 dotpos++;
8387
8388 const size_t partpos =
8389 34204 fullname.find(RDB_PARTITION_STR, dotpos, strlen(RDB_PARTITION_STR));
8390
8391
2/2
✓ Branch 0 taken 13891 times.
✓ Branch 1 taken 20313 times.
34204 if (partpos != std::string::npos) {
8392
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13891 times.
13891 assert(partpos >= dotpos);
8393
8394
2/2
✓ Branch 0 taken 8691 times.
✓ Branch 1 taken 5200 times.
13891 if (table != nullptr) {
8395 8691 *table = fullname.substr(dotpos, partpos - dotpos);
8396 }
8397
8398
2/2
✓ Branch 0 taken 8691 times.
✓ Branch 1 taken 5200 times.
13891 if (partition != nullptr) {
8399 8691 *partition = fullname.substr(partpos + strlen(RDB_PARTITION_STR));
8400 }
8401
2/2
✓ Branch 0 taken 15257 times.
✓ Branch 1 taken 5056 times.
20313 } else if (table != nullptr) {
8402 15257 *table = fullname.substr(dotpos);
8403 }
8404
8405 34204 return HA_EXIT_SUCCESS;
8406 }
8407
8408 /*
8409 Generates the normalized tablename using as many of the given arguments as
8410 possible. Any of the three arguments to <db>.<table>#P#<partition> can be
8411 null/empty, but return string will only ever be of the form
8412 <db>
8413 <db>.<table>
8414 <db>.<table>#P#<partition>
8415 <table>
8416 <table>#P#<partition>
8417 */
8418 2500 void rdb_gen_normalized_tablename(const std::string *db,
8419 const std::string *table,
8420 const std::string *partition,
8421 std::string *fullname) {
8422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2500 times.
2500 if (!fullname) return;
8423 2500 fullname->clear();
8424
3/6
✓ Branch 0 taken 2500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2500 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2500 times.
✗ Branch 5 not taken.
2500 if (db && db->length() > 0) *fullname += *db;
8425
8426 /* If table was not passed in, the partition will be ignored too */
8427
3/6
✓ Branch 0 taken 2500 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2500 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2500 times.
2500 if (!table || table->length() == 0) return;
8428
8429
1/2
✓ Branch 0 taken 2500 times.
✗ Branch 1 not taken.
2500 if (fullname->length() > 0) *fullname += ".";
8430 2500 *fullname += *table;
8431
8432
5/6
✓ Branch 0 taken 2500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1553 times.
✓ Branch 3 taken 947 times.
✓ Branch 4 taken 1553 times.
✓ Branch 5 taken 947 times.
2500 if (partition && partition->length() > 0) {
8433
3/6
✓ Branch 0 taken 1553 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1553 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1553 times.
✗ Branch 5 not taken.
1553 *fullname += std::string(RDB_PARTITION_STR) + *partition;
8434 }
8435 }
8436
8437 /*
8438 Create a table's Rdb_tbl_def and its Rdb_key_defs and store table information
8439 into MyRocks Data Dictionary
8440 The method is called during create table/partition, truncate table/partition
8441
8442 @param table_name IN table's name formated as
8443 'dbname.tablename'
8444 @param actual_user_table_name IN actual table name in case
8445 of alter table copy algorithm
8446 @param table_arg IN sql table
8447 @param auto_increment_value IN specified table's auto increment value
8448
8449 @return
8450 HA_EXIT_SUCCESS OK
8451 other HA_ERR error code (can be SE-specific)
8452 */
8453 14718 int ha_rocksdb::create_table(const std::string &table_name,
8454 const std::string &actual_user_table_name,
8455 const TABLE *table_arg,
8456 ulonglong auto_increment_value,
8457 dd::Table *table_def MY_ATTRIBUTE((__unused__))) {
8458
1/2
✓ Branch 0 taken 14718 times.
✗ Branch 1 not taken.
14718 DBUG_ENTER_FUNC();
8459
8460 int err;
8461
1/2
✓ Branch 0 taken 14718 times.
✗ Branch 1 not taken.
14718 auto local_dict_manager = dict_manager.get_dict_manager_selector_non_const(
8462 14718 is_tmp_table(table_name));
8463
1/2
✓ Branch 0 taken 14718 times.
✗ Branch 1 not taken.
14718 const std::unique_ptr<rocksdb::WriteBatch> wb = local_dict_manager->begin();
8464 14718 rocksdb::WriteBatch *const batch = wb.get();
8465
8466 /* Create table/key descriptions and put them into the data dictionary */
8467
2/4
✓ Branch 0 taken 14718 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14718 times.
✗ Branch 3 not taken.
14718 m_tbl_def = new Rdb_tbl_def(table_name);
8468
8469 14718 uint n_keys = table_arg->s->keys;
8470
8471 /*
8472 If no primary key found, create a hidden PK and place it inside table
8473 definition
8474 */
8475
3/4
✓ Branch 0 taken 14718 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5956 times.
✓ Branch 3 taken 8762 times.
14718 if (has_hidden_pk(table_arg)) {
8476 5956 n_keys += 1;
8477 // reset hidden pk id
8478 // the starting valid value for hidden pk is 1
8479 5956 m_tbl_def->m_hidden_pk_val = 1;
8480 }
8481
8482
4/6
✓ Branch 0 taken 14718 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14718 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26906 times.
✓ Branch 5 taken 14718 times.
41624 m_key_descr_arr = new std::shared_ptr<Rdb_key_def>[n_keys];
8483 14718 m_tbl_def->m_key_count = n_keys;
8484 14718 m_tbl_def->m_pk_index = table_arg->s->primary_key;
8485 14718 m_tbl_def->m_key_descr_arr = m_key_descr_arr;
8486
8487
1/2
✓ Branch 0 taken 14715 times.
✗ Branch 1 not taken.
14718 err = create_key_defs(table_arg, m_tbl_def, actual_user_table_name);
8488
2/2
✓ Branch 0 taken 241 times.
✓ Branch 1 taken 14474 times.
14715 if (err != HA_EXIT_SUCCESS) {
8489 241 goto error;
8490 }
8491
8492
1/2
✓ Branch 0 taken 14474 times.
✗ Branch 1 not taken.
14474 m_pk_descr = m_key_descr_arr[pk_index(table_arg, m_tbl_def)];
8493
8494
2/2
✓ Branch 0 taken 509 times.
✓ Branch 1 taken 13965 times.
14474 if (auto_increment_value) {
8495 509 bool autoinc_upgrade_test = false;
8496 509 m_tbl_def->m_auto_incr_val = auto_increment_value;
8497
2/4
✓ Branch 0 taken 509 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 509 times.
509 DBUG_EXECUTE_IF("myrocks_autoinc_upgrade", autoinc_upgrade_test = true;);
8498
1/2
✓ Branch 0 taken 509 times.
✗ Branch 1 not taken.
509 if (!autoinc_upgrade_test) {
8499 auto s = local_dict_manager->put_auto_incr_val(
8500 509 batch, m_tbl_def->get_autoincr_gl_index_id(),
8501
2/4
✓ Branch 0 taken 509 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 509 times.
✗ Branch 3 not taken.
509 m_tbl_def->m_auto_incr_val);
8502
2/4
✓ Branch 0 taken 509 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 509 times.
509 if (!s.ok()) {
8503 goto error;
8504 }
8505
1/2
✓ Branch 0 taken 509 times.
✗ Branch 1 not taken.
509 }
8506 }
8507
8508
6/10
✓ Branch 0 taken 14474 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 14471 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
14474 DBUG_EXECUTE_IF("rocksdb_create_table", {
8509 THD *const thd = my_core::thd_get_current_thd();
8510 static constexpr char act[] =
8511 "now signal ready_to_mark_cf_dropped_in_create_table "
8512 "wait_for mark_cf_dropped_done_in_create_table";
8513 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
8514 });
8515
8516 {
8517
1/2
✓ Branch 0 taken 14474 times.
✗ Branch 1 not taken.
14474 std::lock_guard<Rdb_dict_manager> dm_lock(*local_dict_manager);
8518
1/2
✓ Branch 0 taken 14474 times.
✗ Branch 1 not taken.
14474 err = ddl_manager.put_and_write(m_tbl_def, batch);
8519
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 14471 times.
14474 if (err != HA_EXIT_SUCCESS) {
8520 3 goto error;
8521 }
8522
8523
1/2
✓ Branch 0 taken 14471 times.
✗ Branch 1 not taken.
14471 err = local_dict_manager->commit(batch);
8524
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14471 times.
14471 if (err != HA_EXIT_SUCCESS) {
8525 goto error;
8526 }
8527
2/2
✓ Branch 0 taken 14471 times.
✓ Branch 1 taken 3 times.
14474 }
8528
8529
1/2
✓ Branch 0 taken 14471 times.
✗ Branch 1 not taken.
14471 DBUG_RETURN(HA_EXIT_SUCCESS);
8530
8531 244 error:
8532 /* Delete what we have allocated so far */
8533
1/2
✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
244 delete m_tbl_def;
8534 244 m_tbl_def = nullptr;
8535 244 m_key_descr_arr = nullptr;
8536
8537
1/2
✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
244 DBUG_RETURN(err);
8538 14715 }
8539
8540 /**
8541 @brief
8542 create() is called to create a table. The variable name will have the name
8543 of the table.
8544
8545 @details
8546 When create() is called you do not need to worry about
8547 opening the table. Also, the DD table have already been
8548 created so adjusting create_info is not necessary.
8549
8550 Called from handle.cc by ha_create_table().
8551
8552 @return
8553 HA_EXIT_SUCCESS OK
8554 other HA_ERR error code (can be SE-specific)
8555
8556 @see
8557 ha_create_table() in handle.cc
8558 */
8559
8560 14479 int ha_rocksdb::create(const char *const name, TABLE *const table_arg,
8561 HA_CREATE_INFO *const create_info,
8562 dd::Table *table_def) {
8563
1/2
✓ Branch 0 taken 14479 times.
✗ Branch 1 not taken.
14479 DBUG_ENTER_FUNC();
8564
8565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14479 times.
14479 assert(table_arg != nullptr);
8566
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14479 times.
14479 assert(create_info != nullptr);
8567
8568
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 14470 times.
14479 if (unlikely(create_info->data_file_name)) {
8569 // DATA DIRECTORY is used to create tables under a specific location
8570 // outside the MySQL data directory. We don't support this for MyRocks.
8571 // The `rocksdb_datadir` setting should be used to configure RocksDB data
8572 // directory.
8573
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 DBUG_RETURN(HA_ERR_ROCKSDB_TABLE_DATA_DIRECTORY_NOT_SUPPORTED);
8574 }
8575
8576
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 14464 times.
14470 if (unlikely(create_info->index_file_name)) {
8577 // Similar check for INDEX DIRECTORY as well.
8578
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_RETURN(HA_ERR_ROCKSDB_TABLE_INDEX_DIRECTORY_NOT_SUPPORTED);
8579 }
8580
8581
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14464 times.
14464 if (unlikely(create_info->tablespace)) {
8582 my_error(ER_NOT_SUPPORTED_YET, MYF(0),
8583 "TABLESPACEs for the RocksDB storage engine");
8584 DBUG_RETURN(HA_WRONG_CREATE_OPTION);
8585 }
8586
8587
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14464 times.
14464 if (unlikely(create_info->compress.length)) {
8588 my_error(ER_NOT_SUPPORTED_YET, MYF(0),
8589 "InnoDB page COMPRESSION for the RocksDB storage engine");
8590 DBUG_RETURN(HA_WRONG_CREATE_OPTION);
8591 }
8592
8593
4/4
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 14370 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 14460 times.
14558 if (unlikely(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
8594
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 90 times.
94 !rocksdb_enable_tmp_table) {
8595
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
8596
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 ha_resolve_storage_engine_name(create_info->db_type), "TEMPORARY");
8597
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 DBUG_RETURN(HA_ERR_ROCKSDB_INVALID_TABLE);
8598 }
8599
8600 int err;
8601 /*
8602 Construct dbname.tablename ourselves, because parititioning
8603 passes strings like "./test/t14#P#p0" for individual partitions,
8604 while table_arg->s->table_name has none of that.
8605 */
8606 14460 std::string str;
8607
2/4
✓ Branch 0 taken 14460 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14460 times.
✗ Branch 3 not taken.
14460 err = rdb_normalize_tablename(name, &str);
8608
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14460 times.
14460 if (err != HA_EXIT_SUCCESS) {
8609 DBUG_RETURN(err);
8610 }
8611
8612 // FOREIGN KEY isn't supported yet
8613
1/2
✓ Branch 0 taken 14460 times.
✗ Branch 1 not taken.
14460 THD *const thd = my_core::thd_get_current_thd();
8614
3/4
✓ Branch 0 taken 14460 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 14448 times.
14460 if (contains_foreign_key(thd)) {
8615
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 my_error(ER_NOT_SUPPORTED_YET, MYF(0),
8616 "FOREIGN KEY for the RocksDB storage engine");
8617
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 DBUG_RETURN(HA_ERR_UNSUPPORTED);
8618 }
8619
8620 // Check whether Data Dictionary contain information
8621
1/2
✓ Branch 0 taken 14448 times.
✗ Branch 1 not taken.
14448 Rdb_tbl_def *old_tbl = ddl_manager.find(str);
8622
2/2
✓ Branch 0 taken 2230 times.
✓ Branch 1 taken 12218 times.
14448 if (old_tbl != nullptr) {
8623
2/2
✓ Branch 0 taken 2224 times.
✓ Branch 1 taken 6 times.
2230 if (thd->lex->sql_command == SQLCOM_TRUNCATE) {
8624
2/4
✓ Branch 0 taken 2224 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2221 times.
✗ Branch 3 not taken.
2224 DBUG_RETURN(truncate_table(old_tbl, create_info->actual_user_table_name,
8625 table_arg, create_info->auto_increment_value,
8626 table_def));
8627 } else {
8628
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 my_error(ER_METADATA_INCONSISTENCY, MYF(0), str.c_str());
8629
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_RETURN(HA_ERR_ROCKSDB_CORRUPT_DATA);
8630 }
8631 }
8632
2/4
✓ Branch 0 taken 12218 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12218 times.
✗ Branch 3 not taken.
12218 DBUG_RETURN(create_table(str, create_info->actual_user_table_name, table_arg,
8633 create_info->auto_increment_value, table_def));
8634 14457 }
8635
8636 /*
8637 Fast truncates a table by renaming the old table, creating a new one and
8638 restoring or deleting the old table based on the results from creation.
8639
8640 @param tbl_def IN MyRocks's table structure
8641 @param actual_user_table_name IN actual table name in case
8642 @param table_arg IN sql table
8643 @param auto_increment_value IN specified table's auto increment value
8644
8645 @return
8646 HA_EXIT_SUCCESS OK
8647 other HA_ERR error code (can be SE-specific)
8648 */
8649 2500 int ha_rocksdb::truncate_table(Rdb_tbl_def *tbl_def_arg,
8650 const std::string &actual_user_table_name,
8651 TABLE *table_arg, ulonglong auto_increment_value,
8652 dd::Table *table_def) {
8653
1/2
✓ Branch 0 taken 2500 times.
✗ Branch 1 not taken.
2500 DBUG_ENTER_FUNC();
8654
8655 /*
8656 Fast table truncation involves deleting the table and then recreating
8657 it. However, it is possible recreating the table fails. In this case, a
8658 table inconsistency might result between SQL and MyRocks where MyRocks is
8659 missing a table. Since table creation involves modifying keys with the
8660 original table name, renaming the original table first, and then renaming
8661 it back in case of creation failure can help restore the pre-truncation
8662 state.
8663
8664 If the server were to crash during truncation, the system will end up with
8665 an inconsistency. Future changes for atomic ddl will resolve this. For now,
8666 if there are any truncation renamed tables found during startup, MyRocks
8667 will automatically remove them.
8668 */
8669
1/2
✓ Branch 0 taken 2500 times.
✗ Branch 1 not taken.
2500 std::string orig_tablename = tbl_def_arg->full_tablename();
8670 2500 std::string dbname, tblname, partition;
8671
8672 /*
8673 Rename the table in the data dictionary. Since this thread should be
8674 holding the MDL for this tablename, it is safe to perform these renames
8675 should be locked via MDL, no other process thread be able to access this
8676 table.
8677 */
8678
1/2
✓ Branch 0 taken 2500 times.
✗ Branch 1 not taken.
2500 int err = rdb_split_normalized_tablename(orig_tablename, &dbname, &tblname,
8679 &partition);
8680
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2500 times.
2500 assert(err == 0);
8681
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2500 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2500 if (err != HA_EXIT_SUCCESS) DBUG_RETURN(err);
8682
2/4
✓ Branch 0 taken 2500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2500 times.
✗ Branch 3 not taken.
2500 tblname = std::string(TRUNCATE_TABLE_PREFIX) + tblname;
8683
8684 2500 std::string tmp_tablename;
8685
1/2
✓ Branch 0 taken 2500 times.
✗ Branch 1 not taken.
2500 rdb_gen_normalized_tablename(&dbname, &tblname, &partition, &tmp_tablename);
8686
8687
1/2
✓ Branch 0 taken 2500 times.
✗ Branch 1 not taken.
2500 err = rename_table(orig_tablename.c_str(), tmp_tablename.c_str(), table_def,
8688 table_def);
8689
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2500 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2500 if (err != HA_EXIT_SUCCESS) DBUG_RETURN(err);
8690
8691 /*
8692 Attempt to create the table. If this succeeds, then drop the old table.
8693 Otherwise, try to restore it.
8694 */
8695
1/2
✓ Branch 0 taken 2497 times.
✗ Branch 1 not taken.
2500 err = create_table(orig_tablename, actual_user_table_name, table_arg,
8696 auto_increment_value, table_def);
8697 2497 bool should_remove_old_table = true;
8698
8699 /* Restore the old table being truncated if creating the new table failed */
8700
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2488 times.
2497 if (err != HA_EXIT_SUCCESS) {
8701
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 int rename_err = rename_table(tmp_tablename.c_str(), orig_tablename.c_str(),
8702 table_def, table_def);
8703
8704 /*
8705 If the rename also fails, we are out of options, but at least try to drop
8706 the old table contents.
8707 */
8708
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (rename_err == HA_EXIT_SUCCESS) {
8709 9 should_remove_old_table = false;
8710 } else {
8711 LogPluginErrMsg(ERROR_LEVEL, 0,
8712 "Failure during truncation of table %s "
8713 "being renamed from %s",
8714 orig_tablename.c_str(), tmp_tablename.c_str());
8715 err = rename_err;
8716 }
8717 }
8718
8719 /*
8720 Since the table was successfully truncated or the name restore failed, no
8721 error should be returned at this point from trying to delete the old
8722 table. If the delete_table fails, log it instead.
8723 */
8724
1/2
✓ Branch 0 taken 2497 times.
✗ Branch 1 not taken.
2497 Rdb_tbl_def *old_tbl_def = ddl_manager.find(tmp_tablename);
8725
3/4
✓ Branch 0 taken 2488 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 2488 times.
✗ Branch 3 not taken.
2497 if (should_remove_old_table && old_tbl_def) {
8726 2488 m_tbl_def = old_tbl_def;
8727
2/4
✓ Branch 0 taken 2488 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2488 times.
2488 if (delete_table(old_tbl_def) != HA_EXIT_SUCCESS) {
8728 LogPluginErrMsg(ERROR_LEVEL, 0,
8729 "Failure when trying to drop table %s during "
8730 "truncation of table %s",
8731 tmp_tablename.c_str(), orig_tablename.c_str());
8732 }
8733 }
8734
8735 /* Update the local m_tbl_def reference */
8736
1/2
✓ Branch 0 taken 2497 times.
✗ Branch 1 not taken.
2497 m_tbl_def = ddl_manager.find(orig_tablename);
8737
3/6
✓ Branch 0 taken 2497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2497 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2497 times.
✗ Branch 5 not taken.
2497 m_converter.reset(new Rdb_converter(ha_thd(), m_tbl_def, table_arg));
8738
1/2
✓ Branch 0 taken 2497 times.
✗ Branch 1 not taken.
2497 DBUG_RETURN(err);
8739 2497 }
8740
8741 /**
8742 @note
8743 This function is used only when the table has not yet been opened, and
8744 keyread_allowed bitmap doesn't have the correct values yet.
8745
8746 See comment in ha_rocksdb::index_flags() for details.
8747 */
8748
8749 2190307 bool ha_rocksdb::check_keyread_allowed(bool &pk_can_be_decoded,
8750 const TABLE_SHARE *, uint, uint, bool) {
8751 /*
8752 (TODO) Remove this function and index version checks, Also remove return
8753 code from Rdb_field_packing:setup() and remove the changes for '[mysql80]
8754 Issue #108: Index-only scans do not work for partitioned tables and
8755 extended keys'.
8756
8757 For the cases of `create table t1 (a varchar(64), key (a(32)))`
8758 and text/blob key columns, the sql layer seems to handle them
8759 correctly regarding using index. InnoDB also seems to return
8760 HA_KEYREAD_ONLY for these cases.
8761 */
8762 2190307 pk_can_be_decoded = true;
8763 2190307 return true;
8764 }
8765
8766 /**
8767 @note
8768 The problem with this function is that SQL layer calls it, when
8769 - the table has not been yet opened (no ::open() call done)
8770 - this->table_share already exists, but it is in the process of being
8771 filled, so some of fields are still NULL.
8772 - In particular, table_share->key_info[inx].key_part[] is filled only up
8773 to part #part. Subsequent key parts are not yet filled.
8774
8775 To complicate things further, SQL layer will call index_flags() with
8776 all_parts=true. Essentially, we're asked to provide flags for reading
8777 keyparts whose datatype is not yet known.
8778
8779 We walk around this problem by using check_keyread_allowed(), which uses
8780 table_share object and is careful not to step on unitialized data.
8781
8782 When we get a call with all_parts=true, we try to analyze all parts but
8783 ignore those that have key_part->field==nullptr (these are not initialized
8784 yet).
8785 */
8786
8787 2173362 ulong ha_rocksdb::index_flags(bool &pk_can_be_decoded,
8788 const TABLE_SHARE *table_share, uint inx,
8789 uint part, bool all_parts) {
8790
1/2
✓ Branch 0 taken 2173362 times.
✗ Branch 1 not taken.
2173362 DBUG_ENTER_FUNC();
8791
8792 2173362 ulong base_flags = HA_READ_NEXT | // doesn't seem to be used
8793 HA_READ_ORDER | HA_READ_RANGE | HA_READ_PREV;
8794
1/2
✓ Branch 0 taken 2173362 times.
✗ Branch 1 not taken.
2173362 bool res = check_keyread_allowed(pk_can_be_decoded, table_share, inx, part,
8795 all_parts);
8796
1/2
✓ Branch 0 taken 2173362 times.
✗ Branch 1 not taken.
2173362 if (res) base_flags |= HA_KEYREAD_ONLY;
8797
8798
2/2
✓ Branch 0 taken 1665470 times.
✓ Branch 1 taken 507892 times.
2173362 if (inx == table_share->primary_key) {
8799 /*
8800 Index-only reads on primary key are the same as table scan for us. Still,
8801 we need to explicitly "allow" them, otherwise SQL layer will miss some
8802 plans.
8803 */
8804 1665470 base_flags |= HA_KEYREAD_ONLY;
8805
1/2
✓ Branch 0 taken 507892 times.
✗ Branch 1 not taken.
507892 } else if (res) {
8806 /* We can do ICP only if we are able to decode the key (res == true) */
8807 /*
8808 We can Index Condition Pushdown any key except the primary. With primary
8809 key, we get (pk, record) pair immediately, there is no place to put the
8810 ICP check.
8811 */
8812 507892 base_flags |= HA_DO_INDEX_COND_PUSHDOWN;
8813 }
8814
8815
1/2
✓ Branch 0 taken 2173362 times.
✗ Branch 1 not taken.
2173362 DBUG_RETURN(base_flags);
8816 }
8817
8818 2129604 ulong ha_rocksdb::index_flags(uint inx, uint part, bool all_parts) const {
8819 2129604 return index_flags(m_pk_can_be_decoded, table_share, inx, part, all_parts);
8820 }
8821
8822 /**
8823 @brief
8824 Read from primary key if secondary key is not covering.
8825
8826 @details
8827 m_scan_it points at the index key-value pair that we should read the (pk,row)
8828 pair for.
8829 */
8830 52475729 int ha_rocksdb::secondary_index_read(const int keyno, uchar *const buf,
8831 const rocksdb::Slice *value,
8832 bool *skip_row) {
8833
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52475729 times.
52475729 assert(buf != nullptr);
8834
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52475729 times.
52475729 assert(table != nullptr);
8835
8836 52475729 int rc = 0;
8837
8838 #ifndef NDEBUG
8839 52475729 bool save_keyread_only = m_keyread_only;
8840
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 52475726 times.
52475729 DBUG_EXECUTE_IF("dbug.rocksdb.HA_EXTRA_KEYREAD", { m_keyread_only = true; });
8841 #endif
8842 bool covered_lookup =
8843
4/4
✓ Branch 0 taken 40350427 times.
✓ Branch 1 taken 12125302 times.
✓ Branch 2 taken 9431 times.
✓ Branch 3 taken 40340996 times.
64610462 (m_keyread_only && m_key_descr_arr[keyno]->can_cover_lookup()) ||
8844
2/2
✓ Branch 0 taken 13323 times.
✓ Branch 1 taken 12121410 times.
12134733 m_key_descr_arr[keyno]->covers_lookup(value,
8845 52475729 m_converter->get_lookup_bitmap());
8846 #ifndef NDEBUG
8847 52475729 m_keyread_only = save_keyread_only;
8848 #endif
8849
8850
4/4
✓ Branch 0 taken 40354319 times.
✓ Branch 1 taken 12121410 times.
✓ Branch 2 taken 40349069 times.
✓ Branch 3 taken 5250 times.
52475729 if (covered_lookup && m_lock_rows == RDB_LOCK_NONE) {
8851 40349069 inc_covered_sk_lookup();
8852 } else {
8853
1/2
✓ Branch 0 taken 12126660 times.
✗ Branch 1 not taken.
12126660 DEBUG_SYNC(ha_thd(), "rocksdb_concurrent_delete_sk");
8854 12126660 rc = get_row_by_rowid(buf, m_last_rowkey.ptr(), m_last_rowkey.length(),
8855 skip_row);
8856 }
8857
8858 52475729 return rc;
8859 }
8860
8861 /*
8862 See storage/rocksdb/rocksdb-range-access.txt for description of how MySQL
8863 index navigation commands are converted into RocksDB lookup commands.
8864
8865 MyRocks needs to decide whether prefix bloom filter can be used or not.
8866 To decide to use prefix bloom filter or not, calculating equal condition
8867 length is needed. On equal lookups (find_flag == HA_READ_KEY_EXACT), equal
8868 condition length is the same as rocksdb::Slice.size() of the start key.
8869 On range scan, equal condition length is MIN(start_key, end_key) of the
8870 rocksdb::Slice expression, where end_key is taken from end_range.
8871
8872 @return
8873 HA_EXIT_SUCCESS OK
8874 other HA_ERR error code (can be SE-specific)
8875 */
8876 430614 int ha_rocksdb::index_read_intern(uchar *const buf, const uchar *const key,
8877 key_part_map keypart_map,
8878 enum ha_rkey_function find_flag) {
8879
1/2
✓ Branch 0 taken 430614 times.
✗ Branch 1 not taken.
430614 DBUG_ENTER_FUNC();
8880
8881
1/2
✓ Branch 0 taken 430614 times.
✗ Branch 1 not taken.
430614 check_build_decoder();
8882
8883 430614 int rc = 0;
8884 430614 table->set_no_row();
8885
8886
1/2
✓ Branch 0 taken 430614 times.
✗ Branch 1 not taken.
430614 THD *thd = ha_thd();
8887
2/4
✓ Branch 0 taken 430614 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 430614 times.
✗ Branch 3 not taken.
430614 DEBUG_SYNC(thd, "rocksdb.check_flags_iri");
8888
5/6
✓ Branch 0 taken 430614 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 430611 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 430611 times.
430614 if (thd && thd->killed) {
8889 3 rc = HA_ERR_QUERY_INTERRUPTED;
8890
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(rc);
8891 }
8892
8893
1/2
✓ Branch 0 taken 430611 times.
✗ Branch 1 not taken.
430611 switch (find_flag) {
8894 430611 case HA_READ_KEY_EXACT:
8895 case HA_READ_AFTER_KEY:
8896 case HA_READ_KEY_OR_NEXT:
8897 case HA_READ_BEFORE_KEY:
8898 case HA_READ_PREFIX_LAST:
8899 case HA_READ_PREFIX_LAST_OR_PREV:
8900 430611 break;
8901 default:
8902 DBUG_RETURN(HA_ERR_UNSUPPORTED);
8903 }
8904
8905
1/2
✓ Branch 0 taken 430611 times.
✗ Branch 1 not taken.
430611 const Rdb_key_def &kd = *m_key_descr_arr[active_index_pos()];
8906 430611 bool using_full_key = false;
8907 430611 m_full_key_lookup = false;
8908
8909 uint packed_size;
8910
8911
2/2
✓ Branch 0 taken 32465 times.
✓ Branch 1 taken 398146 times.
430611 if (!key) {
8912 // If no key is passed in, then we are doing a full index scan.
8913 //
8914 // Just use current index id as the search key.
8915 32465 kd.get_infimum_key(m_sk_packed_tuple, &packed_size);
8916 } else {
8917 398146 const uint actual_key_parts = kd.get_key_parts();
8918 398146 using_full_key = is_using_full_key(keypart_map, actual_key_parts);
8919 /*
8920 Handle some special cases when we do exact key lookups.
8921 */
8922
4/4
✓ Branch 0 taken 388749 times.
✓ Branch 1 taken 9397 times.
✓ Branch 2 taken 167875 times.
✓ Branch 3 taken 220874 times.
398146 if (find_flag == HA_READ_KEY_EXACT && using_full_key) {
8923
2/2
✓ Branch 0 taken 162835 times.
✓ Branch 1 taken 5040 times.
167875 if (active_index == table->s->primary_key) {
8924 /*
8925 Equality lookup over primary key, using full tuple.
8926 This is a special case, use DB::Get.
8927 */
8928
1/2
✓ Branch 0 taken 162835 times.
✗ Branch 1 not taken.
162835 const uint size = kd.pack_index_tuple(
8929 table, m_pack_buffer, m_pk_packed_tuple, key, keypart_map);
8930
1/2
✓ Branch 0 taken 162835 times.
✗ Branch 1 not taken.
162835 bool skip_lookup = is_blind_delete_enabled();
8931 /* TODO(yzha) - row stats are gone in 8.0
8932 stats.rows_requested++; */
8933
8934
1/2
✓ Branch 0 taken 162835 times.
✗ Branch 1 not taken.
162835 rc = get_row_by_rowid(buf, m_pk_packed_tuple, size, nullptr,
8935 skip_lookup, false);
8936
4/4
✓ Branch 0 taken 162493 times.
✓ Branch 1 taken 342 times.
✓ Branch 2 taken 162490 times.
✓ Branch 3 taken 3 times.
162835 if (!rc && !skip_lookup) {
8937 /* TODO(yzha) - row stats are gone in 8.0
8938 stats.rows_read++;
8939 stats.rows_index_first++; */
8940
1/2
✓ Branch 0 taken 162490 times.
✗ Branch 1 not taken.
162490 update_row_stats(ROWS_READ);
8941 }
8942 /*
8943 If the SQL layer calls index_read_map, it expects the iterator to be
8944 positioned accordingly, so that next/prev can work as expected. In
8945 this case, we calling DB::Get directly without positioning an
8946 iterator, so it is incorrect for the SQL layer to be calling
8947 next/prev anyway. To avoid correctness issues, just free the
8948 iterator.
8949 */
8950 162835 m_full_key_lookup = true;
8951
1/2
✓ Branch 0 taken 162835 times.
✗ Branch 1 not taken.
162835 m_iterator->reset();
8952
1/2
✓ Branch 0 taken 162835 times.
✗ Branch 1 not taken.
162835 DBUG_RETURN(rc);
8953 } else {
8954 /*
8955 The SQL layer sometimes sets HA_WHOLE_KEY for secondary keys lookups,
8956 even though it may not include extended keys.
8957
8958 Adjust keypart_map so that we get the correct packing.
8959 */
8960
2/2
✓ Branch 0 taken 4650 times.
✓ Branch 1 taken 390 times.
5040 if (keypart_map == HA_WHOLE_KEY) {
8961 4650 uint avail_key_parts = 0;
8962
1/2
✓ Branch 0 taken 4650 times.
✗ Branch 1 not taken.
4650 calculate_key_len(table, active_index, keypart_map, &avail_key_parts);
8963 4650 keypart_map = make_prev_keypart_map(avail_key_parts);
8964 4650 using_full_key = is_using_full_key(keypart_map, actual_key_parts);
8965 }
8966
8967
2/2
✓ Branch 0 taken 1686 times.
✓ Branch 1 taken 3354 times.
5040 if (table->key_info[active_index].flags & HA_NOSAME &&
8968
3/4
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 1470 times.
✓ Branch 2 taken 216 times.
✗ Branch 3 not taken.
1686 m_insert_with_update && m_dup_key_found &&
8969
1/2
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
216 active_index == m_dupp_errkey) {
8970 /*
8971 We are in INSERT ... ON DUPLICATE KEY UPDATE, and this is a read
8972 that SQL layer does to read the duplicate key.
8973 Its rowid is saved in m_last_rowkey. Get the full record and
8974 return it.
8975 */
8976
8977 #ifndef NDEBUG
8978
1/2
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
216 packed_size = kd.pack_index_tuple(
8979 table, m_pack_buffer, m_sk_packed_tuple, key, keypart_map);
8980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 assert(m_dup_key_tuple.length() >= packed_size);
8981
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 assert(memcmp(m_dup_key_tuple.ptr(), m_sk_packed_tuple,
8982 packed_size) == 0);
8983 #endif
8984
8985
1/2
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
216 rc = get_row_by_rowid(buf, m_last_rowkey.ptr(),
8986 216 m_last_rowkey.length());
8987
1/2
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
216 m_iterator->reset();
8988
1/2
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
216 DBUG_RETURN(rc);
8989 }
8990
8991
2/2
✓ Branch 0 taken 390 times.
✓ Branch 1 taken 4434 times.
4824 if (using_full_key) {
8992
1/2
✓ Branch 0 taken 390 times.
✗ Branch 1 not taken.
390 packed_size = kd.pack_index_tuple(
8993 table, m_pack_buffer, m_sk_packed_tuple, key, keypart_map);
8994 rocksdb::Slice key_slice(
8995 390 reinterpret_cast<const char *>(m_sk_packed_tuple), packed_size);
8996
8997
1/2
✓ Branch 0 taken 390 times.
✗ Branch 1 not taken.
390 rc = get_row_by_sk(buf, kd, &key_slice);
8998
8999
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 18 times.
390 if (!rc) {
9000 /* TODO(yzha) - row stats are gone in 8.0
9001 stats.rows_read++;
9002 stats.rows_index_first++; */
9003
1/2
✓ Branch 0 taken 372 times.
✗ Branch 1 not taken.
372 update_row_stats(ROWS_READ);
9004 }
9005
9006 390 m_full_key_lookup = true;
9007
1/2
✓ Branch 0 taken 390 times.
✗ Branch 1 not taken.
390 m_iterator->reset();
9008
1/2
✓ Branch 0 taken 390 times.
✗ Branch 1 not taken.
390 DBUG_RETURN(rc);
9009 }
9010 }
9011 }
9012
9013
1/2
✓ Branch 0 taken 234705 times.
✗ Branch 1 not taken.
234705 packed_size = kd.pack_index_tuple(table, m_pack_buffer, m_sk_packed_tuple,
9014 key, keypart_map);
9015 }
9016
9017 267170 rocksdb::Slice slice(reinterpret_cast<const char *>(m_sk_packed_tuple),
9018 267170 packed_size);
9019
9020 267170 rocksdb::Slice end_slice;
9021
6/6
✓ Branch 0 taken 92852 times.
✓ Branch 1 taken 174318 times.
✓ Branch 2 taken 3845 times.
✓ Branch 3 taken 89007 times.
✓ Branch 4 taken 3826 times.
✓ Branch 5 taken 19 times.
267170 if (end_range && find_flag != HA_READ_KEY_EXACT &&
9022 find_flag != HA_READ_PREFIX_LAST) {
9023 3826 uint end_key_packed_size = 0;
9024 end_key_packed_size =
9025 7652 kd.pack_index_tuple(table, m_pack_buffer, m_end_key_packed_tuple,
9026
1/2
✓ Branch 0 taken 3826 times.
✗ Branch 1 not taken.
3826 end_range->key, end_range->keypart_map);
9027 3826 end_slice =
9028 3826 rocksdb::Slice((char *)m_end_key_packed_tuple, end_key_packed_size);
9029 }
9030
9031
1/2
✓ Branch 0 taken 267170 times.
✗ Branch 1 not taken.
267170 Rdb_transaction *const tx = get_or_create_tx(table->in_use);
9032 267170 const bool is_new_snapshot = !tx->has_snapshot();
9033
9034 // Loop as long as we get a deadlock error AND we end up creating the
9035 // snapshot here (i.e. it did not exist prior to this)
9036 for (;;) {
9037
2/4
✓ Branch 0 taken 267191 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 267191 times.
✗ Branch 3 not taken.
267191 DEBUG_SYNC(thd, "rocksdb.check_flags_iri_scan");
9038
5/6
✓ Branch 0 taken 267191 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 267188 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 267188 times.
267191 if (thd && thd->killed) {
9039 3 rc = HA_ERR_QUERY_INTERRUPTED;
9040 3 break;
9041 }
9042 /*
9043 This will open the iterator and position it at a record that's equal or
9044 greater than the lookup tuple.
9045 */
9046
1/2
✓ Branch 0 taken 267188 times.
✗ Branch 1 not taken.
267188 rc = m_iterator->seek(find_flag, slice, using_full_key, end_slice);
9047
9048
2/2
✓ Branch 0 taken 9792 times.
✓ Branch 1 taken 257396 times.
267188 if (rc) {
9049 9792 break;
9050 }
9051
9052 /*
9053 Now get the data for the row into 'buf'. If we were using a primary key
9054 then we have all the rows we need. For a secondary key we now need to
9055 lookup the primary key.
9056 */
9057
2/2
✓ Branch 0 taken 3992 times.
✓ Branch 1 taken 3675 times.
7667 bool direction = (find_flag == HA_READ_KEY_EXACT) ||
9058
4/4
✓ Branch 0 taken 7667 times.
✓ Branch 1 taken 249729 times.
✓ Branch 2 taken 2607 times.
✓ Branch 3 taken 1385 times.
265063 (find_flag == HA_READ_AFTER_KEY) ||
9059 (find_flag == HA_READ_KEY_OR_NEXT);
9060
1/2
✓ Branch 0 taken 257396 times.
✗ Branch 1 not taken.
257396 rc = index_next_with_direction_intern(buf, direction, true);
9061
9062
3/4
✓ Branch 0 taken 257396 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 257375 times.
✓ Branch 3 taken 21 times.
257396 if (!should_recreate_snapshot(rc, is_new_snapshot)) {
9063 257375 break; /* Exit the loop */
9064 }
9065
9066 // release the snapshot and iterator so they will be regenerated
9067
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 tx->release_snapshot();
9068
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 m_iterator->reset();
9069 21 }
9070
9071 if (!rc) {
9072 /* TODO(yzha) - row stats are gone in 8.0
9073 stats.rows_index_first++;
9074 stats.rows_index_next--; */
9075 }
9076
9077
1/2
✓ Branch 0 taken 267170 times.
✗ Branch 1 not taken.
267170 DBUG_RETURN(rc);
9078 }
9079
9080 /*
9081 See storage/rocksdb/rocksdb-range-access.txt for description of how MySQL
9082 index navigation commands are converted into RocksDB lookup commands.
9083
9084 MyRocks needs to decide whether prefix bloom filter can be used or not.
9085 To decide to use prefix bloom filter or not, calculating equal condition
9086 length is needed. On equal lookups (find_flag == HA_READ_KEY_EXACT), equal
9087 condition length is the same as rocksdb::Slice.size() of the start key.
9088 On range scan, equal condition length is MIN(start_key, end_key) of the
9089 rocksdb::Slice expression, where end_key is taken from end_range.
9090
9091 @return
9092 HA_EXIT_SUCCESS OK
9093 other HA_ERR error code (can be SE-specific)
9094 */
9095 398149 int ha_rocksdb::index_read_map(uchar *const buf, const uchar *const key,
9096 key_part_map keypart_map,
9097 enum ha_rkey_function find_flag) {
9098
1/2
✓ Branch 0 taken 398149 times.
✗ Branch 1 not taken.
398149 DBUG_ENTER_FUNC();
9099
1/2
✓ Branch 0 taken 398149 times.
✗ Branch 1 not taken.
398149 ha_statistic_increment(&System_status_var::ha_read_key_count);
9100
9101
1/2
✓ Branch 0 taken 398149 times.
✗ Branch 1 not taken.
398149 int rc = index_read_intern(buf, key, keypart_map, find_flag);
9102
9103 // The SQL layer generally expects HA_ERR_KEY_NOT_FOUND for this call.
9104
2/2
✓ Branch 0 taken 2771 times.
✓ Branch 1 taken 395378 times.
398149 if (rc == HA_ERR_END_OF_FILE) {
9105 2771 rc = HA_ERR_KEY_NOT_FOUND;
9106 }
9107
9108
1/2
✓ Branch 0 taken 398149 times.
✗ Branch 1 not taken.
398149 DBUG_RETURN(rc);
9109 }
9110
9111 /**
9112 @return
9113 HA_EXIT_SUCCESS OK
9114 other HA_ERR error code (can be SE-specific)
9115 */
9116 341 int ha_rocksdb::index_read_last_map(uchar *const buf, const uchar *const key,
9117 key_part_map keypart_map) {
9118
1/2
✓ Branch 0 taken 341 times.
✗ Branch 1 not taken.
341 DBUG_ENTER_FUNC();
9119
9120
2/4
✓ Branch 0 taken 341 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 341 times.
✗ Branch 3 not taken.
682 DBUG_RETURN(index_read_map(buf, key, keypart_map, HA_READ_PREFIX_LAST));
9121 }
9122
9123 /**
9124 @return
9125 HA_ADMIN_OK OK
9126 other HA_ADMIN error code
9127 */
9128 123 int ha_rocksdb::check(THD *const thd, HA_CHECK_OPT *const check_opt) {
9129
1/2
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
123 DBUG_ENTER_FUNC();
9130
9131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
123 assert(thd != nullptr);
9132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
123 assert(check_opt != nullptr);
9133
9134 123 const uint pk = table->s->primary_key;
9135 123 String rowkey_copy;
9136 123 String sec_key_copy;
9137 123 const char *const table_name = table->s->table_name.str;
9138
9139 // Only when debugging: don't use snapshot when reading
9140 // Rdb_transaction *tx= get_or_create_tx(table->in_use);
9141 // tx->snapshot= nullptr;
9142
9143 bool save_verify_row_debug_checksums =
9144 123 m_converter->get_verify_row_debug_checksums();
9145 123 m_converter->set_verify_row_debug_checksums(true);
9146 /* For each secondary index, check that we can get a PK value from it */
9147
9/18
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 123 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 123 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 123 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 123 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 123 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 123 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 123 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 123 times.
✗ Branch 17 not taken.
123 LogPluginErrMsg(INFORMATION_LEVEL, 0, "CHECKTABLE %s: Checking table %s",
9148 table_name, table_name);
9149 123 ha_rows row_checksums_at_start = 0; // set/used iff first_index==true
9150 123 ha_rows row_checksums = ha_rows(-1);
9151 123 bool first_index = true;
9152
9153
2/2
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 123 times.
330 for (uint keyno = 0; keyno < table->s->keys; keyno++) {
9154
2/2
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 48 times.
207 if (keyno != pk) {
9155
1/2
✓ Branch 0 taken 159 times.
✗ Branch 1 not taken.
159 extra(HA_EXTRA_KEYREAD);
9156
1/2
✓ Branch 0 taken 159 times.
✗ Branch 1 not taken.
159 ha_index_init(keyno, true);
9157 159 ha_rows rows = 0;
9158 159 m_validated_checksums = 0;
9159
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 63 times.
159 if (first_index) {
9160 96 row_checksums_at_start = m_converter->get_row_checksums_checked();
9161 }
9162 int res;
9163
9/18
✓ Branch 0 taken 159 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 159 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 159 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 159 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 159 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 159 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 159 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 159 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 159 times.
✗ Branch 17 not taken.
159 LogPluginErrMsg(INFORMATION_LEVEL, 0,
9164 "CHECKTABLE %s: Checking index %s", table_name,
9165 table->key_info[keyno].name);
9166 while (1) {
9167
2/2
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 24531 times.
24690 if (!rows) {
9168
1/2
✓ Branch 0 taken 159 times.
✗ Branch 1 not taken.
159 res = index_first(table->record[0]);
9169 } else {
9170
1/2
✓ Branch 0 taken 24531 times.
✗ Branch 1 not taken.
24531 res = index_next(table->record[0]);
9171 }
9172
9173
2/2
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 24531 times.
24690 if (res == HA_ERR_END_OF_FILE) break;
9174
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24531 times.
24531 if (res) {
9175 // error
9176 LogPluginErrMsg(ERROR_LEVEL, 0,
9177 "CHECKTABLE %s: .. row %lld: index scan error %d",
9178 table_name, rows, res);
9179 goto error;
9180 }
9181
1/2
✓ Branch 0 taken 24531 times.
✗ Branch 1 not taken.
24531 rocksdb::Slice key = m_iterator->key();
9182
1/2
✓ Branch 0 taken 24531 times.
✗ Branch 1 not taken.
24531 sec_key_copy.copy(key.data(), key.size(), &my_charset_bin);
9183
1/2
✓ Branch 0 taken 24531 times.
✗ Branch 1 not taken.
24531 rowkey_copy.copy(m_last_rowkey.ptr(), m_last_rowkey.length(),
9184 &my_charset_bin);
9185
9186
2/4
✓ Branch 0 taken 24531 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24531 times.
24531 if ((res = get_row_by_rowid(table->record[0], rowkey_copy.ptr(),
9187 24531 rowkey_copy.length()))) {
9188 LogPluginErrMsg(
9189 ERROR_LEVEL, 0,
9190 "CHECKTABLE %s: .. row %lld: failed to fetch row by rowid",
9191 table_name, rows);
9192 goto error;
9193 }
9194
9195 24531 longlong hidden_pk_id = 0;
9196
4/6
✓ Branch 0 taken 24531 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 420 times.
✓ Branch 3 taken 24111 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24531 times.
24951 if (has_hidden_pk(table) &&
9197
2/4
✓ Branch 0 taken 420 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 420 times.
420 read_hidden_pk_id_from_rowkey(&hidden_pk_id)) {
9198 goto error;
9199 }
9200
9201 /* Check if we get the same PK value */
9202 24531 uint packed_size = m_pk_descr->pack_record(
9203
1/2
✓ Branch 0 taken 24531 times.
✗ Branch 1 not taken.
24531 table, m_pack_buffer, table->record[0], m_pk_packed_tuple, nullptr,
9204 false, hidden_pk_id);
9205
2/4
✓ Branch 0 taken 24531 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24531 times.
49062 if (packed_size != rowkey_copy.length() ||
9206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24531 times.
24531 memcmp(m_pk_packed_tuple, rowkey_copy.ptr(), packed_size)) {
9207 LogPluginErrMsg(ERROR_LEVEL, 0,
9208 "CHECKTABLE %s: .. row %lld: PK value mismatch",
9209 table_name, rows);
9210 goto print_and_error;
9211 }
9212
9213 /* Check if we get the same secondary key value */
9214 24531 packed_size = m_key_descr_arr[keyno]->pack_record(
9215
1/2
✓ Branch 0 taken 24531 times.
✗ Branch 1 not taken.
24531 table, m_pack_buffer, table->record[0], m_sk_packed_tuple,
9216 &m_sk_tails, false, hidden_pk_id);
9217
2/4
✓ Branch 0 taken 24531 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24531 times.
49062 if (packed_size != sec_key_copy.length() ||
9218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24531 times.
24531 memcmp(m_sk_packed_tuple, sec_key_copy.ptr(), packed_size)) {
9219 LogPluginErrMsg(
9220 ERROR_LEVEL, 0,
9221 "CHECKTABLE %s: .. row %lld: secondary index value mismatch",
9222 table_name, rows);
9223 goto print_and_error;
9224 }
9225 24531 rows++;
9226 24531 continue;
9227
9228 print_and_error : {
9229 std::string buf;
9230 buf = rdb_hexdump(rowkey_copy.ptr(), rowkey_copy.length(),
9231 RDB_MAX_HEXDUMP_LEN);
9232 LogPluginErrMsg(ERROR_LEVEL, 0, "CHECKTABLE %s: rowkey: %s",
9233 table_name, buf.c_str());
9234
9235 buf = rdb_hexdump(m_retrieved_record.data(), m_retrieved_record.size(),
9236 RDB_MAX_HEXDUMP_LEN);
9237 LogPluginErrMsg(ERROR_LEVEL, 0, "CHECKTABLE %s: record: %s",
9238 table_name, buf.c_str());
9239
9240 buf = rdb_hexdump(sec_key_copy.ptr(), sec_key_copy.length(),
9241 RDB_MAX_HEXDUMP_LEN);
9242 LogPluginErrMsg(ERROR_LEVEL, 0, "CHECKTABLE %s: index: %s",
9243 table_name, buf.c_str());
9244
9245 goto error;
9246 }
9247 24531 }
9248
9/18
✓ Branch 0 taken 159 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 159 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 159 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 159 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 159 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 159 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 159 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 159 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 159 times.
✗ Branch 17 not taken.
159 LogPluginErrMsg(INFORMATION_LEVEL, 0,
9249 "CHECKTABLE %s: ... %lld index entries checked (%lld "
9250 "had checksums)",
9251 table_name, rows, m_validated_checksums);
9252
9253
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 63 times.
159 if (first_index) {
9254 96 row_checksums =
9255 96 m_converter->get_row_checksums_checked() - row_checksums_at_start;
9256 96 first_index = false;
9257 }
9258
1/2
✓ Branch 0 taken 159 times.
✗ Branch 1 not taken.
159 ha_index_end();
9259 }
9260 }
9261
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 27 times.
123 if (row_checksums != ha_rows(-1)) {
9262
9/18
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 96 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 96 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 96 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 96 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 96 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 96 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 96 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 96 times.
✗ Branch 17 not taken.
96 LogPluginErrMsg(INFORMATION_LEVEL, 0,
9263 "CHECKTABLE %s: %lld table records had checksums",
9264 table_name, row_checksums);
9265 }
9266
1/2
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
123 extra(HA_EXTRA_NO_KEYREAD);
9267
9268 123 m_converter->set_verify_row_debug_checksums(save_verify_row_debug_checksums);
9269 /*
9270 TODO: we should check also for PK records that are missing in the secondary
9271 indexes.
9272 For that, need to walk through the PK and check that every PK record has a
9273 proper counterpart in each secondary index.
9274 */
9275
1/2
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
123 DBUG_RETURN(HA_ADMIN_OK);
9276 error:
9277 m_converter->set_verify_row_debug_checksums(save_verify_row_debug_checksums);
9278 ha_index_or_rnd_end();
9279 extra(HA_EXTRA_NO_KEYREAD);
9280
9281 DBUG_RETURN(HA_ADMIN_CORRUPT);
9282 123 }
9283
9284 static void dbug_dump_str(FILE *const out, const char *const str, int len) {
9285 fprintf(out, "\"");
9286 for (int i = 0; i < len; i++) {
9287 if (str[i] > 32) {
9288 fprintf(out, "%c", str[i]);
9289 } else {
9290 fprintf(out, "\\%d", str[i]);
9291 }
9292 }
9293 fprintf(out, "\"");
9294 }
9295
9296 /*
9297 Debugging help: dump the whole database into a human-readable file.
9298 Usage:
9299 dbug_dump_database(rdb);
9300 */
9301
9302 void dbug_dump_database(rocksdb::DB *const db) {
9303 FILE *const out = fopen("/tmp/rocksdb.dump", "wt");
9304 if (!out) return;
9305
9306 rocksdb::Iterator *it = db->NewIterator(rocksdb::ReadOptions());
9307 for (it->SeekToFirst(); it->Valid(); it->Next()) {
9308 rocksdb::Slice key = it->key();
9309 rocksdb::Slice val = it->value();
9310 dbug_dump_str(out, key.data(), key.size());
9311 fprintf(out, " -> ");
9312 dbug_dump_str(out, val.data(), val.size());
9313 fprintf(out, "\n");
9314 }
9315
9316 delete it;
9317 fclose(out);
9318 }
9319
9320 3873 rocksdb::Status ha_rocksdb::get_for_update(Rdb_transaction *const tx,
9321 const Rdb_key_def &key_descr,
9322 const rocksdb::Slice &key) const {
9323
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3873 times.
3873 assert(m_lock_rows != RDB_LOCK_NONE);
9324
9325 3873 bool exclusive = m_lock_rows != RDB_LOCK_READ;
9326 3873 bool skip_wait =
9327
2/4
✓ Branch 0 taken 3873 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3873 times.
3873 m_locked_row_action == THR_NOWAIT || m_locked_row_action == THR_SKIP;
9328 return rdb_tx_get_for_update(tx, key_descr, key, nullptr, exclusive,
9329 3873 skip_wait);
9330 }
9331
9332 162835 bool ha_rocksdb::is_blind_delete_enabled() {
9333 162835 THD *thd = ha_thd();
9334 162835 return (THDVAR(thd, blind_delete_primary_key) &&
9335
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 thd->lex->sql_command == SQLCOM_DELETE &&
9336
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 thd->lex->table_count == 1 && table->s->keys == 1 &&
9337
4/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 162832 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
162838 !has_hidden_pk(table) && !thd->rli_slave);
9338 }
9339
9340 /*
9341 Given a rowid (i.e. packed PK) as a parameter, get the record.
9342
9343 @return
9344 HA_EXIT_SUCCESS OK
9345 other HA_ERR error code (can be SE-specific)
9346 */
9347
9348 16320090 int ha_rocksdb::get_row_by_rowid(uchar *const buf, const char *const rowid,
9349 const uint rowid_size, bool *skip_row,
9350 const bool skip_lookup,
9351 const bool skip_ttl_check) {
9352
1/2
✓ Branch 0 taken 16320090 times.
✗ Branch 1 not taken.
16320090 DBUG_ENTER_FUNC();
9353
9354
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16320090 times.
16320090 assert(buf != nullptr);
9355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16320090 times.
16320090 assert(rowid != nullptr);
9356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16320090 times.
16320090 assert(table != nullptr);
9357
9358 int rc;
9359
9360
2/2
✓ Branch 0 taken 16010221 times.
✓ Branch 1 taken 309869 times.
16320090 if (skip_row) {
9361 16010221 *skip_row = false;
9362 }
9363
9364 16320090 rocksdb::Slice key_slice(rowid, rowid_size);
9365
9366
1/2
✓ Branch 0 taken 16320090 times.
✗ Branch 1 not taken.
16320090 Rdb_transaction *const tx = get_or_create_tx(table->in_use);
9367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16320090 times.
16320090 assert(tx != nullptr);
9368
9369
3/6
✓ Branch 0 taken 16320090 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16320090 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16320090 times.
✗ Branch 5 not taken.
16320090 DEBUG_SYNC(ha_thd(), "rocksdb.get_row_by_rowid");
9370
7/12
✓ Branch 0 taken 16320090 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 16320084 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 6 times.
16320090 DBUG_EXECUTE_IF("dbug.rocksdb.get_row_by_rowid", {
9371 THD *thd = ha_thd();
9372 static constexpr char act[] =
9373 "now signal Reached "
9374 "wait_for signal.rocksdb.get_row_by_rowid_let_running";
9375 assert(opt_debug_sync_timeout > 0);
9376 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
9377 };);
9378
9379 /* Pretend row found without looking up */
9380
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 16320087 times.
16320090 if (skip_lookup) {
9381
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 update_row_stats(ROWS_DELETED_BLIND);
9382
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 m_last_rowkey.copy((const char *)rowid, rowid_size, &my_charset_bin);
9383
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(0);
9384 }
9385
9386
5/6
✓ Branch 0 taken 377 times.
✓ Branch 1 taken 16319710 times.
✓ Branch 2 taken 377 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 161 times.
✓ Branch 5 taken 16319926 times.
16320464 if (m_insert_with_update && m_dup_key_found &&
9387
2/2
✓ Branch 0 taken 161 times.
✓ Branch 1 taken 216 times.
377 m_pk_descr->get_keyno() == m_dupp_errkey) {
9388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 161 times.
161 assert(m_lock_rows == RDB_LOCK_WRITE);
9389
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 161 times.
161 assert(m_dup_key_tuple.length() == key_slice.size());
9390
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 161 times.
161 assert(
9391 memcmp(m_dup_key_tuple.ptr(), key_slice.data(), key_slice.size()) == 0);
9392
9393 // We have stored the record with duplicate key in
9394 // m_dup_key_retrieved_record during write_row already, so just move it
9395 // over.
9396
1/2
✓ Branch 0 taken 161 times.
✗ Branch 1 not taken.
161 m_retrieved_record = std::move(m_dup_key_retrieved_record);
9397 161 rc = HA_EXIT_SUCCESS;
9398 } else {
9399
1/2
✓ Branch 0 taken 16319926 times.
✗ Branch 1 not taken.
16319926 tx->acquire_snapshot(false);
9400 16319926 bool skip_wait =
9401
4/4
✓ Branch 0 taken 16319884 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 16319776 times.
16319926 m_locked_row_action == THR_NOWAIT || m_locked_row_action == THR_SKIP;
9402
2/4
✓ Branch 0 taken 16319926 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16319926 times.
✗ Branch 3 not taken.
16319926 rc = get_pk_iterator()->get(&key_slice, &m_retrieved_record, m_lock_rows,
9403 skip_ttl_check, skip_wait);
9404 }
9405
9406
2/2
✓ Branch 0 taken 16319473 times.
✓ Branch 1 taken 614 times.
16320087 if (!rc) {
9407
1/2
✓ Branch 0 taken 16319473 times.
✗ Branch 1 not taken.
16319473 m_last_rowkey.copy((const char *)rowid, rowid_size, &my_charset_bin);
9408
1/2
✓ Branch 0 taken 16319473 times.
✗ Branch 1 not taken.
16319473 rc = convert_record_from_storage_format(&key_slice, buf);
9409
9410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16319473 times.
16319473 if (rc) {
9411 DBUG_RETURN(rc);
9412 }
9413
9414
1/2
✓ Branch 0 taken 16319473 times.
✗ Branch 1 not taken.
16319473 rc = fill_virtual_columns();
9415
3/4
✓ Branch 0 taken 614 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 569 times.
614 } else if (should_skip_locked_record(rc)) {
9416
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45 if (skip_row) {
9417 45 *skip_row = true;
9418 }
9419
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45 DBUG_RETURN(HA_ERR_KEY_NOT_FOUND);
9420 }
9421
9422 /*
9423 Note: we don't need to unlock the row. It is intentional that we keep
9424 locks on rows that don't exist.
9425 */
9426
1/2
✓ Branch 0 taken 16320042 times.
✗ Branch 1 not taken.
16320042 DBUG_RETURN(rc);
9427 }
9428
9429 600 int ha_rocksdb::records(ha_rows *num_rows) {
9430
2/2
✓ Branch 0 taken 591 times.
✓ Branch 1 taken 9 times.
600 if (m_lock_rows == RDB_LOCK_NONE) {
9431 // SELECT COUNT(*) without locking, fast path
9432 591 m_iteration_only = true;
9433 auto iteration_guard =
9434
1/2
✓ Branch 0 taken 591 times.
✗ Branch 1 not taken.
591 create_scope_guard([this]() { m_iteration_only = false; });
9435
1/2
✓ Branch 0 taken 591 times.
✗ Branch 1 not taken.
591 return handler::records(num_rows);
9436 591 } else {
9437 // SELECT COUNT(*) with locking, slow path
9438 9 return handler::records(num_rows);
9439 }
9440 }
9441
9442 721 int ha_rocksdb::records_from_index(ha_rows *num_rows, uint index) {
9443
2/2
✓ Branch 0 taken 712 times.
✓ Branch 1 taken 9 times.
721 if (m_lock_rows == RDB_LOCK_NONE) {
9444 // SELECT COUNT(*) without locking, fast path
9445 712 m_iteration_only = true;
9446 auto iteration_guard =
9447
1/2
✓ Branch 0 taken 712 times.
✗ Branch 1 not taken.
712 create_scope_guard([this]() { m_iteration_only = false; });
9448
1/2
✓ Branch 0 taken 712 times.
✗ Branch 1 not taken.
712 return handler::records_from_index(num_rows, index);
9449 712 } else {
9450 // SELECT COUNT(*) with locking, slow path
9451 9 return handler::records_from_index(num_rows, index);
9452 }
9453 }
9454
9455 /*
9456 The analagous function to ha_rocksdb::get_row_by_rowid for performing
9457 secondary key lookups.
9458
9459 @return
9460 HA_EXIT_SUCCESS OK
9461 other HA_ERR error code (can be SE-specific)
9462 */
9463 390 int ha_rocksdb::get_row_by_sk(uchar *buf, const Rdb_key_def &kd,
9464 const rocksdb::Slice *key) {
9465
1/2
✓ Branch 0 taken 390 times.
✗ Branch 1 not taken.
390 DBUG_ENTER_FUNC();
9466
9467
1/2
✓ Branch 0 taken 390 times.
✗ Branch 1 not taken.
390 int rc = m_iterator->get(key, &m_retrieved_record, RDB_LOCK_NONE);
9468
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 372 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
390 if (rc) DBUG_RETURN(rc);
9469
9470 const uint size =
9471
1/2
✓ Branch 0 taken 372 times.
✗ Branch 1 not taken.
372 kd.get_primary_key_tuple(*m_pk_descr, key, m_pk_packed_tuple);
9472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 372 times.
372 if (size == RDB_INVALID_KEY_LEN) {
9473 DBUG_RETURN(HA_ERR_ROCKSDB_CORRUPT_DATA);
9474 }
9475
9476
1/2
✓ Branch 0 taken 372 times.
✗ Branch 1 not taken.
372 m_last_rowkey.copy((const char *)m_pk_packed_tuple, size, &my_charset_bin);
9477
9478
1/2
✓ Branch 0 taken 372 times.
✗ Branch 1 not taken.
372 rc = secondary_index_read(active_index, buf, &m_retrieved_record, nullptr);
9479
1/2
✓ Branch 0 taken 372 times.
✗ Branch 1 not taken.
372 if (!rc) {
9480 372 table->set_found_row();
9481 }
9482
1/2
✓ Branch 0 taken 372 times.
✗ Branch 1 not taken.
372 DBUG_RETURN(rc);
9483 }
9484
9485 /**
9486 @return
9487 HA_EXIT_SUCCESS OK
9488 other HA_ERR error code (can be SE-specific)
9489 */
9490 88945623 int ha_rocksdb::index_next(uchar *const buf) {
9491
1/2
✓ Branch 0 taken 88945623 times.
✗ Branch 1 not taken.
88945623 DBUG_ENTER_FUNC();
9492
9493
1/2
✓ Branch 0 taken 88945623 times.
✗ Branch 1 not taken.
88945623 check_build_decoder();
9494
9495
1/2
✓ Branch 0 taken 88945623 times.
✗ Branch 1 not taken.
88945623 ha_statistic_increment(&System_status_var::ha_read_next_count);
9496
2/4
✓ Branch 0 taken 88945623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 88945623 times.
✗ Branch 3 not taken.
177891246 DBUG_RETURN(index_next_with_direction_intern(buf, true, false));
9497 }
9498
9499 /**
9500 @return
9501 HA_EXIT_SUCCESS OK
9502 other HA_ERR error code (can be SE-specific)
9503 */
9504 371663 int ha_rocksdb::index_next_same(uchar *const buf,
9505 const uchar *key MY_ATTRIBUTE((unused)),
9506 uint keylen MY_ATTRIBUTE((unused))) {
9507
1/2
✓ Branch 0 taken 371663 times.
✗ Branch 1 not taken.
371663 DBUG_ENTER_FUNC();
9508
9509
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 371657 times.
371663 if (m_full_key_lookup) {
9510 #ifndef NDEBUG
9511
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 uint len = calculate_key_len(table, active_index, HA_WHOLE_KEY);
9512
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 assert(len == keylen);
9513 #endif
9514
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_RETURN(HA_ERR_END_OF_FILE);
9515 }
9516
2/4
✓ Branch 0 taken 371657 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 371657 times.
✗ Branch 3 not taken.
371657 DBUG_RETURN(index_next(buf));
9517 }
9518
9519 /**
9520 @return
9521 HA_EXIT_SUCCESS OK
9522 other HA_ERR error code (can be SE-specific)
9523 */
9524 93386 int ha_rocksdb::index_prev(uchar *const buf) {
9525
1/2
✓ Branch 0 taken 93386 times.
✗ Branch 1 not taken.
93386 DBUG_ENTER_FUNC();
9526
9527
1/2
✓ Branch 0 taken 93386 times.
✗ Branch 1 not taken.
93386 check_build_decoder();
9528
9529
1/2
✓ Branch 0 taken 93386 times.
✗ Branch 1 not taken.
93386 ha_statistic_increment(&System_status_var::ha_read_prev_count);
9530
2/4
✓ Branch 0 taken 93386 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 93386 times.
✗ Branch 3 not taken.
186772 DBUG_RETURN(index_next_with_direction_intern(buf, false, false));
9531 }
9532
9533 /**
9534 This function handles all the logic for reading out the next row given a valid
9535 iterator, and populates buf with the next row on success. This includes
9536 filtering logic (eg. ICP, TTL, etc.), locking and reading from the PK to
9537 obtain full row if necessary.
9538
9539 The skip_next parameter determines whether we need to advance the iterator at
9540 least once. Generally, callers that are seeking (eg.
9541 index_first/index_read_map/etc.) will set skip_next to true, since the
9542 iterator is already at the correct position and may not need advancement.
9543 Callers that are iterating to the next key (eg. index_next/index_prev/etc.)
9544 will set skip_next to false since the iterator needs to be advanced at least
9545 once.
9546
9547 The move_forward parameter controls the direction of iteration.
9548
9549 @return
9550 HA_EXIT_SUCCESS OK
9551 other HA_ERR error code (can be SE-specific)
9552 */
9553 186325145 int ha_rocksdb::index_next_with_direction_intern(uchar *const buf,
9554 bool move_forward,
9555 bool skip_next) {
9556
1/2
✓ Branch 0 taken 186325145 times.
✗ Branch 1 not taken.
186325145 DBUG_ENTER_FUNC();
9557
9558
1/2
✓ Branch 0 taken 186325145 times.
✗ Branch 1 not taken.
186325145 THD *thd = ha_thd();
9559 186325145 int rc = 0;
9560
1/2
✓ Branch 0 taken 186325145 times.
✗ Branch 1 not taken.
186325145 const Rdb_key_def &kd = *m_key_descr_arr[active_index_pos()];
9561
9562 186325145 table->set_no_row();
9563 /* TODO(yzha) - row stats are gone in 8.0
9564 stats.rows_requested++; */
9565
9566 for (;;) {
9567
2/4
✓ Branch 0 taken 186325478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 186325478 times.
✗ Branch 3 not taken.
186325478 DEBUG_SYNC(thd, "rocksdb.check_flags_inwdi");
9568
5/6
✓ Branch 0 taken 186325478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 186325472 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 186325472 times.
186325478 if (thd && thd->killed) {
9569 6 rc = HA_ERR_QUERY_INTERRUPTED;
9570 6 break;
9571 }
9572
9573
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 186325472 times.
186325472 assert(m_iterator != nullptr);
9574
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 186325472 times.
186325472 if (m_iterator == nullptr) {
9575 rc = HA_ERR_INTERNAL_ERROR;
9576 break;
9577 }
9578
9579
2/2
✓ Branch 0 taken 257390 times.
✓ Branch 1 taken 186068082 times.
186325472 if (skip_next) {
9580 257390 skip_next = false;
9581 } else {
9582
2/2
✓ Branch 0 taken 161943964 times.
✓ Branch 1 taken 24124118 times.
186068082 if (move_forward) {
9583
1/2
✓ Branch 0 taken 161943964 times.
✗ Branch 1 not taken.
161943964 rc = m_iterator->next();
9584 } else {
9585
1/2
✓ Branch 0 taken 24124118 times.
✗ Branch 1 not taken.
24124118 rc = m_iterator->prev();
9586 }
9587 }
9588
9589
2/2
✓ Branch 0 taken 241327 times.
✓ Branch 1 taken 186084145 times.
186325472 if (rc) {
9590 241327 break;
9591 }
9592
9593
1/2
✓ Branch 0 taken 186084145 times.
✗ Branch 1 not taken.
186084145 const rocksdb::Slice &key = m_iterator->key();
9594
1/2
✓ Branch 0 taken 186084145 times.
✗ Branch 1 not taken.
186084145 const rocksdb::Slice &value = m_iterator->value();
9595
9596
2/2
✓ Branch 0 taken 58270514 times.
✓ Branch 1 taken 127813631 times.
186084145 if (m_iteration_only) {
9597 58270514 table->set_found_row();
9598 58270514 rc = 0;
9599
2/2
✓ Branch 0 taken 75337678 times.
✓ Branch 1 taken 52475953 times.
127813631 } else if (active_index == table->s->primary_key) {
9600
2/2
✓ Branch 0 taken 3883573 times.
✓ Branch 1 taken 71454105 times.
75337678 if (m_lock_rows != RDB_LOCK_NONE) {
9601
3/6
✓ Branch 0 taken 3883573 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3883573 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3883573 times.
✗ Branch 5 not taken.
3883573 DEBUG_SYNC(ha_thd(), "rocksdb_concurrent_delete");
9602 /* We need to put a lock and re-read */
9603 3883573 bool skip_row = false;
9604
1/2
✓ Branch 0 taken 3883573 times.
✗ Branch 1 not taken.
3883573 rc = get_row_by_rowid(buf, key.data(), key.size(), &skip_row);
9605
4/4
✓ Branch 0 taken 197 times.
✓ Branch 1 taken 3883376 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 161 times.
3883573 if (rc != HA_EXIT_SUCCESS && skip_row) {
9606 // We are asked to skip locked rows
9607 36 continue;
9608 }
9609 } else {
9610 /* Unpack from the row we've read */
9611
1/2
✓ Branch 0 taken 71454105 times.
✗ Branch 1 not taken.
71454105 m_last_rowkey.copy(key.data(), key.size(), &my_charset_bin);
9612
1/2
✓ Branch 0 taken 71454105 times.
✗ Branch 1 not taken.
71454105 rc = convert_record_from_storage_format(&key, &value, buf);
9613 }
9614 } else {
9615
1/2
✓ Branch 0 taken 52475953 times.
✗ Branch 1 not taken.
52475953 rc = kd.unpack_record(table, buf, &key, &value,
9616 52475953 m_converter->get_verify_row_debug_checksums());
9617
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 52475941 times.
52475953 if (rc != HA_EXIT_SUCCESS) {
9618 377 break;
9619 }
9620
9621 // Record did not satisfy ICP, move to next record
9622
3/4
✓ Branch 0 taken 46503 times.
✓ Branch 1 taken 52429438 times.
✓ Branch 2 taken 46503 times.
✗ Branch 3 not taken.
52475941 if (pushed_idx_cond && pushed_idx_cond_keyno == active_index) {
9623
1/2
✓ Branch 0 taken 46503 times.
✗ Branch 1 not taken.
46503 const enum icp_result icp_status = check_index_cond();
9624
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 46284 times.
46503 if (icp_status == ICP_NO_MATCH) {
9625 219 continue;
9626
2/2
✓ Branch 0 taken 365 times.
✓ Branch 1 taken 45919 times.
46284 } else if (icp_status == ICP_OUT_OF_RANGE) {
9627 365 rc = HA_ERR_END_OF_FILE;
9628 365 break;
9629 }
9630
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45919 times.
45919 assert(icp_status == ICP_MATCH);
9631 }
9632
9633 const uint size =
9634
1/2
✓ Branch 0 taken 52475357 times.
✗ Branch 1 not taken.
52475357 kd.get_primary_key_tuple(*m_pk_descr, &key, m_pk_packed_tuple);
9635
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52475357 times.
52475357 if (size == RDB_INVALID_KEY_LEN) {
9636 rc = HA_ERR_ROCKSDB_CORRUPT_DATA;
9637 break;
9638 }
9639
9640
1/2
✓ Branch 0 taken 52475357 times.
✗ Branch 1 not taken.
52475357 m_last_rowkey.copy((const char *)m_pk_packed_tuple, size,
9641 &my_charset_bin);
9642
9643 52475357 bool skip_row = false;
9644
1/2
✓ Branch 0 taken 52475357 times.
✗ Branch 1 not taken.
52475357 rc = secondary_index_read(active_index, buf, &value, &skip_row);
9645
3/4
✓ Branch 0 taken 52475291 times.
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 52475291 times.
52475357 if (!rc && skip_row) {
9646 // SKIP LOCKED
9647 continue;
9648 }
9649 }
9650
9651
3/4
✓ Branch 0 taken 186083513 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 186083435 times.
✓ Branch 3 taken 78 times.
186083513 if (!should_skip_invalidated_record(rc)) {
9652 186083435 break;
9653 }
9654 333 }
9655
9656
2/2
✓ Branch 0 taken 186083274 times.
✓ Branch 1 taken 241871 times.
186325145 if (!rc) {
9657 /* TODO(yzha) - row stats are gone in 8.0
9658 stats.rows_read++;
9659 stats.rows_index_next++; */
9660
1/2
✓ Branch 0 taken 186083274 times.
✗ Branch 1 not taken.
186083274 update_row_stats(ROWS_READ);
9661 186083274 table->set_found_row();
9662 }
9663
9664 // skip_next is false when called from functions that are trying to iterate
9665 // through keys such as index_next/rnd_next/etc. and these functions
9666 // typically expect HA_ERR_END_OF_FILE if no next key is found.
9667
2/2
✓ Branch 0 taken 186325139 times.
✓ Branch 1 taken 6 times.
186325145 if (!skip_next) {
9668
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 186325139 times.
186325139 if (rc == HA_ERR_KEY_NOT_FOUND) {
9669 rc = HA_ERR_END_OF_FILE;
9670 }
9671 }
9672
9673
1/2
✓ Branch 0 taken 186325145 times.
✗ Branch 1 not taken.
186325145 DBUG_RETURN(rc);
9674 }
9675
9676 24661501 Rdb_iterator_base *ha_rocksdb::get_pk_iterator() {
9677
2/2
✓ Branch 0 taken 3418291 times.
✓ Branch 1 taken 21274907 times.
24661501 if (!m_pk_iterator) {
9678 3418458 m_pk_iterator.reset(
9679
2/4
✓ Branch 0 taken 3418574 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3418458 times.
✗ Branch 3 not taken.
3418291 new Rdb_iterator_base(ha_thd(), m_pk_descr, m_pk_descr, m_tbl_def));
9680 }
9681 24693520 return m_pk_iterator.get();
9682 }
9683
9684 /**
9685 @return
9686 HA_EXIT_SUCCESS OK
9687 other HA_ERR error code (can be SE-specific)
9688 */
9689 6811 int ha_rocksdb::index_first(uchar *const buf) {
9690
1/2
✓ Branch 0 taken 6811 times.
✗ Branch 1 not taken.
6811 DBUG_ENTER_FUNC();
9691
9692
1/2
✓ Branch 0 taken 6811 times.
✗ Branch 1 not taken.
6811 check_build_decoder();
9693
9694
1/2
✓ Branch 0 taken 6811 times.
✗ Branch 1 not taken.
6811 ha_statistic_increment(&System_status_var::ha_read_first_count);
9695
2/4
✓ Branch 0 taken 6811 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6811 times.
✗ Branch 3 not taken.
13622 DBUG_RETURN(index_read_intern(buf, true /* first */));
9696 }
9697
9698 /**
9699 @return
9700 HA_EXIT_SUCCESS OK
9701 other HA_ERR error code (can be SE-specific)
9702 */
9703 2436 int ha_rocksdb::index_last(uchar *const buf) {
9704
1/2
✓ Branch 0 taken 2436 times.
✗ Branch 1 not taken.
2436 DBUG_ENTER_FUNC();
9705
9706
1/2
✓ Branch 0 taken 2436 times.
✗ Branch 1 not taken.
2436 check_build_decoder();
9707
9708
1/2
✓ Branch 0 taken 2436 times.
✗ Branch 1 not taken.
2436 ha_statistic_increment(&System_status_var::ha_read_last_count);
9709
2/4
✓ Branch 0 taken 2436 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2436 times.
✗ Branch 3 not taken.
4872 DBUG_RETURN(index_read_intern(buf, false /* first */));
9710 }
9711
9712 /* clang-format off */
9713 /*
9714 index_read_intern is called by handler methods doing full table/index scans
9715 (eg. index_first/index_last).
9716
9717 'first' refers to the logical seek direction in the table.
9718
9719 The implementation simply calls index_read_intern with nullptr as the key
9720 (which will default to using just the index id as the key) with either
9721 HA_READ_KEY_EXACT or HA_READ_PREFIX_LAST, for ascending and descending
9722 respectively. This will automatically give us the correct semantics as
9723 HA_READ_KEY_EXACT will return the first key with the given prefix, whereas
9724 HA_READ_PREFIX_LAST will return the last key with the given prefix.
9725
9726 At a lower level, there are four cases being handled in this function.
9727
9728 1. Seeking to first row of table with forwards cf:
9729
9730 An picture of a forward-ordered keyspace (remember, the keys have form
9731 'indexnr-keyval'. Suppose the index we are at has number n)
9732
9733 (n-1) - ...
9734 ( n ) <--- 1. (n) doesn't exist in the db but it would be here.
9735 ( n ) - aaa <--- 2. Seek("n") will put us here on the first index
9736 ( n ) - bbb record.
9737 ( n ) - cc
9738
9739 So, need to do: Seek(n);
9740
9741 2. Seeking to last row of table with reverse cf:
9742
9743 (n+1) - bbb
9744 (n+1) - aaa
9745 (n+1) <--- (n+1) doesn't exist in the db but would be here.
9746 ( n ) - ccc <--- 1. We need to be here.
9747 ( n ) - bbb
9748 ( n ) - aaa
9749 ( n )
9750
9751 So, need to: Seek(n+1);
9752
9753 3. Seeking to last row of table with forwards cf:
9754
9755 An picture of a forward-ordered keyspace (remember, the keys have form
9756 'indexnr-keyval'. Suppose the we are at a key that has number n)
9757
9758 (n-1)-something
9759 ( n )-aaa
9760 ( n )-bbb
9761 ( n )-ccc <----------- Need to seek to here.
9762 (n+1) <---- Doesn't exist, but would be here.
9763 (n+1)-smth, or no value at all
9764
9765 RocksDB's Iterator::SeekForPrev($val) seeks to "at $val or last value
9766 that's smaller". We can't seek to "(n)-ccc" directly, because we don't know
9767 what is the value of 'ccc' (the biggest record with prefix (n)). Instead, we
9768 seek to "(n+1)", which is the least possible value that's greater than any
9769 value in index #n.
9770
9771 So, need to: it->SeekForPrev(n+1)
9772
9773 4. Seeking to first row of table with reverse cf:
9774
9775 (n+1)-something
9776 ( n ) - ccc
9777 ( n ) - bbb
9778 ( n ) - aaa <---------------- (*) Need to seek here.
9779 ( n ) <--- Doesn't exist, but would be here.
9780 (n-1)-smth, or no value at all
9781
9782 So, need to: it->SeekForPrev(n)
9783 */
9784 /* clang-format on */
9785 32465 int ha_rocksdb::index_read_intern(uchar *const buf, bool first) {
9786
1/2
✓ Branch 0 taken 32465 times.
✗ Branch 1 not taken.
32465 DBUG_ENTER_FUNC();
9787
3/4
✓ Branch 0 taken 29906 times.
✓ Branch 1 taken 2559 times.
✓ Branch 2 taken 32465 times.
✗ Branch 3 not taken.
32465 int rc = index_read_intern(buf, nullptr, 0,
9788 first ? HA_READ_KEY_EXACT : HA_READ_PREFIX_LAST);
9789
9790
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32465 times.
32465 if (rc == HA_ERR_KEY_NOT_FOUND) rc = HA_ERR_END_OF_FILE;
9791
9792
1/2
✓ Branch 0 taken 32465 times.
✗ Branch 1 not taken.
32465 DBUG_RETURN(rc);
9793 }
9794
9795 4174094 void ha_rocksdb::unlock_row() {
9796
1/2
✓ Branch 0 taken 4174094 times.
✗ Branch 1 not taken.
4174094 DBUG_ENTER_FUNC();
9797
9798
2/2
✓ Branch 0 taken 3606811 times.
✓ Branch 1 taken 567283 times.
4174094 if (m_lock_rows != RDB_LOCK_NONE) {
9799
1/2
✓ Branch 0 taken 3606811 times.
✗ Branch 1 not taken.
3606811 Rdb_transaction *const tx = get_or_create_tx(table->in_use);
9800
1/2
✓ Branch 0 taken 3606811 times.
✗ Branch 1 not taken.
3606811 tx->release_lock(*m_pk_descr,
9801
1/2
✓ Branch 0 taken 3606811 times.
✗ Branch 1 not taken.
7213622 std::string(m_last_rowkey.ptr(), m_last_rowkey.length()));
9802 }
9803
9804
1/2
✓ Branch 0 taken 4174094 times.
✗ Branch 1 not taken.
8348188 DBUG_VOID_RETURN;
9805 }
9806
9807 /*
9808 Returning true if SingleDelete can be used.
9809 - Secondary Indexes can always use SingleDelete.
9810 - If the index is PRIMARY KEY, and if all of the columns of the table
9811 are covered by the PRIMARY KEY, SingleDelete can be used.
9812 */
9813 488615 bool ha_rocksdb::can_use_single_delete(const uint index) const {
9814
1/2
✓ Branch 0 taken 488615 times.
✗ Branch 1 not taken.
977230 return (index != pk_index(table, m_tbl_def) ||
9815
2/2
✓ Branch 0 taken 483454 times.
✓ Branch 1 taken 5161 times.
488615 (!has_hidden_pk(table) &&
9816
2/2
✓ Branch 0 taken 104378 times.
✓ Branch 1 taken 379076 times.
972069 table->key_info[index].actual_key_parts == table->s->fields));
9817 }
9818
9819 74662174 bool ha_rocksdb::skip_unique_check() const {
9820 /*
9821 We want to skip unique checks if:
9822 1) bulk_load is on
9823 2) the user set unique_checks option to 0, and the table does not have
9824 any indexes. If the table has secondary keys, then those might becomes
9825 inconsisted/corrupted
9826 3) We're using read-free replication
9827 */
9828 74662174 return THDVAR(table->in_use, bulk_load) ||
9829
2/2
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 12077770 times.
12104281 (my_core::thd_test_options(table->in_use,
9830 186 OPTION_RELAXED_UNIQUE_CHECKS) &&
9831
3/4
✓ Branch 0 taken 12104281 times.
✓ Branch 1 taken 62565435 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4975 times.
86837681 m_tbl_def->m_key_count == 1) ||
9832
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12169885 times.
86811170 use_read_free_rpl();
9833 }
9834
9835 71197875 bool commit_in_the_middle(THD *thd) {
9836 // It does not make sense to use write unprepared with commit in the middle,
9837 // since both handle large transactions by flushing the write batches onto
9838 // disk.
9839 //
9840 // For the two to work together, we would need to assign a new xid after
9841 // committing.
9842
4/4
✓ Branch 0 taken 9061526 times.
✓ Branch 1 taken 62156989 times.
✓ Branch 2 taken 37222 times.
✓ Branch 3 taken 9056532 times.
133392086 return (THDVAR(thd, bulk_load) || THDVAR(thd, commit_in_the_middle)) &&
9843
2/2
✓ Branch 0 taken 42492833 times.
✓ Branch 1 taken 19701378 times.
133444954 rocksdb_write_policy != rocksdb::TxnDBWritePolicy::WRITE_UNPREPARED;
9844 }
9845
9846 /*
9847 Executing bulk commit if it should.
9848 @retval true if bulk commit failed
9849 @retval false if bulk commit was skipped or succeeded
9850 */
9851 70939922 bool ha_rocksdb::do_bulk_commit(Rdb_transaction *const tx) {
9852
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70939922 times.
70939922 assert(tx != nullptr);
9853 70939922 return commit_in_the_middle(table->in_use) &&
9854
4/4
✓ Branch 0 taken 42492695 times.
✓ Branch 1 taken 28495659 times.
✓ Branch 2 taken 478 times.
✓ Branch 3 taken 42462121 times.
70988832 tx->get_write_count() >= THDVAR(table->in_use, bulk_load_size) &&
9855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 478 times.
70958736 tx->flush_batch();
9856 }
9857
9858 /*
9859 If table was created without primary key, SQL layer represents the primary
9860 key number as MAX_INDEXES. Hence, this function returns true if the table
9861 does not contain a primary key. (In which case we generate a hidden
9862 'auto-incremented' pk.)
9863 */
9864 72753233 bool ha_rocksdb::has_hidden_pk(const TABLE *const table) const {
9865
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72753233 times.
72753233 assert(table != nullptr);
9866 72753233 return Rdb_key_def::table_has_hidden_pk(table);
9867 }
9868
9869 /*
9870 Returns true if given index number is a hidden_pk.
9871 - This is used when a table is created with no primary key.
9872 */
9873 138127568 bool ha_rocksdb::is_hidden_pk(const uint index, const TABLE *const table_arg,
9874 const Rdb_tbl_def *const tbl_def_arg) {
9875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 138127568 times.
138127568 assert(table_arg != nullptr);
9876
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 138127568 times.
138127568 assert(table_arg->s != nullptr);
9877
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 138127568 times.
138127568 assert(tbl_def_arg != nullptr);
9878
9879
2/2
✓ Branch 0 taken 7149842 times.
✓ Branch 1 taken 130977726 times.
145277410 return (table_arg->s->primary_key == MAX_INDEXES &&
9880
2/2
✓ Branch 0 taken 1320253 times.
✓ Branch 1 taken 5829589 times.
145277410 index == tbl_def_arg->m_key_count - 1);
9881 }
9882
9883 /* Returns index of primary key */
9884 906995 uint ha_rocksdb::pk_index(const TABLE *const table_arg,
9885 const Rdb_tbl_def *const tbl_def_arg) {
9886
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 906995 times.
906995 assert(table_arg != nullptr);
9887
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 906995 times.
906995 assert(table_arg->s != nullptr);
9888
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 906995 times.
906995 assert(tbl_def_arg != nullptr);
9889
9890
2/2
✓ Branch 0 taken 33315 times.
✓ Branch 1 taken 873680 times.
906995 return table_arg->s->primary_key == MAX_INDEXES ? tbl_def_arg->m_key_count - 1
9891 906995 : table_arg->s->primary_key;
9892 }
9893
9894 /* Returns the index into m_key_descr_arr array based on active_index */
9895 284316166 uint ha_rocksdb::active_index_pos() {
9896
2/2
✓ Branch 0 taken 652015 times.
✓ Branch 1 taken 283664151 times.
284316166 return active_index == MAX_KEY ? m_tbl_def->m_key_count - 1 : active_index;
9897 }
9898
9899 /* Returns true if given index number is a primary key */
9900 145214052 bool ha_rocksdb::is_pk(const uint index, const TABLE *const table_arg,
9901 const Rdb_tbl_def *const tbl_def_arg) {
9902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 145214052 times.
145214052 assert(table_arg != nullptr);
9903
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 145214052 times.
145214052 assert(table_arg->s != nullptr);
9904
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 145214052 times.
145214052 assert(tbl_def_arg != nullptr);
9905
9906
2/2
✓ Branch 0 taken 66617158 times.
✓ Branch 1 taken 78596894 times.
211831210 return index == table_arg->s->primary_key ||
9907
2/2
✓ Branch 0 taken 847516 times.
✓ Branch 1 taken 65769642 times.
211831210 is_hidden_pk(index, table_arg, tbl_def_arg);
9908 }
9909
9910 18432 uint ha_rocksdb::max_supported_key_part_length(
9911 HA_CREATE_INFO *create_info MY_ATTRIBUTE((__unused__))) const {
9912
1/2
✓ Branch 0 taken 18432 times.
✗ Branch 1 not taken.
18432 DBUG_ENTER_FUNC();
9913
3/4
✓ Branch 0 taken 18432 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18384 times.
✓ Branch 3 taken 48 times.
18432 DBUG_RETURN(rocksdb_large_prefix ? MAX_INDEX_COL_LEN_LARGE
9914 : MAX_INDEX_COL_LEN_SMALL);
9915 }
9916
9917 29952 const char *ha_rocksdb::get_key_name(const uint index,
9918 const TABLE *const table_arg,
9919 const Rdb_tbl_def *const tbl_def_arg) {
9920
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29952 times.
29952 assert(table_arg != nullptr);
9921
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29952 times.
29952 assert(tbl_def_arg != nullptr);
9922
9923
2/2
✓ Branch 0 taken 6460 times.
✓ Branch 1 taken 23492 times.
29952 if (is_hidden_pk(index, table_arg, tbl_def_arg)) {
9924 6460 return HIDDEN_PK_NAME;
9925 }
9926
9927
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23492 times.
23492 assert(table_arg->key_info != nullptr);
9928
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23492 times.
23492 assert(table_arg->key_info[index].name != nullptr);
9929
9930 23492 return table_arg->key_info[index].name;
9931 }
9932
9933 28329 const char *ha_rocksdb::get_key_comment(const uint index,
9934 const TABLE *const table_arg,
9935 const Rdb_tbl_def *const tbl_def_arg) {
9936
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28329 times.
28329 assert(table_arg != nullptr);
9937
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28329 times.
28329 assert(tbl_def_arg != nullptr);
9938
9939
2/2
✓ Branch 0 taken 6142 times.
✓ Branch 1 taken 22187 times.
28329 if (is_hidden_pk(index, table_arg, tbl_def_arg)) {
9940 6142 return nullptr;
9941 }
9942
9943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22187 times.
22187 assert(table_arg->key_info != nullptr);
9944
9945 22187 return table_arg->key_info[index].comment.str;
9946 }
9947
9948 28329 const std::string ha_rocksdb::generate_cf_name(
9949 const uint index, const TABLE *const table_arg,
9950 const Rdb_tbl_def *const tbl_def_arg, bool *per_part_match_found) {
9951
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28329 times.
28329 assert(table_arg != nullptr);
9952
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28329 times.
28329 assert(tbl_def_arg != nullptr);
9953
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28329 times.
28329 assert(per_part_match_found != nullptr);
9954
9955 // When creating CF-s the caller needs to know if there was a custom CF name
9956 // specified for a given paritition.
9957 28329 *per_part_match_found = false;
9958
9959 // Index comment is used to define the column family name specification(s).
9960 // If there was no comment, we get an emptry string, and it means "use the
9961 // default column family".
9962
1/2
✓ Branch 0 taken 28329 times.
✗ Branch 1 not taken.
28329 const char *const comment = get_key_comment(index, table_arg, tbl_def_arg);
9963
9964 // `get_key_comment` can return `nullptr`, that's why this.
9965
3/4
✓ Branch 0 taken 2200 times.
✓ Branch 1 taken 26129 times.
✓ Branch 2 taken 28329 times.
✗ Branch 3 not taken.
28329 std::string key_comment = comment ? comment : "";
9966
9967 std::string cf_name = Rdb_key_def::parse_comment_for_qualifier(
9968 key_comment, table_arg, tbl_def_arg, per_part_match_found,
9969
1/2
✓ Branch 0 taken 28329 times.
✗ Branch 1 not taken.
28329 RDB_CF_NAME_QUALIFIER);
9970
9971
4/4
✓ Branch 0 taken 12092 times.
✓ Branch 1 taken 16237 times.
✓ Branch 2 taken 11627 times.
✓ Branch 3 taken 465 times.
28329 if (table_arg->part_info != nullptr && !*per_part_match_found) {
9972 // At this point we tried to search for a custom CF name for a partition,
9973 // but none was specified. Therefore default one will be used.
9974
1/2
✓ Branch 0 taken 11627 times.
✗ Branch 1 not taken.
11627 return "";
9975 }
9976
9977 // If we didn't find any partitioned/non-partitioned qualifiers, DO NOT return
9978 // the comment itself. FB 5.6 Behavior is exactly the opposite which then
9979 // causes any index comment to create a new column family.
9980
9981 // Strip leading and trailing whitespace as that is not part of a valid name
9982
3/4
✓ Branch 0 taken 1563 times.
✓ Branch 1 taken 15139 times.
✓ Branch 2 taken 1563 times.
✗ Branch 3 not taken.
16702 if (!cf_name.empty()) rdb_trim_whitespace_from_edges(cf_name);
9983
9984 16702 return cf_name;
9985 28329 }
9986
9987 const std::string ha_rocksdb::get_table_comment(const TABLE *const table_arg) {
9988 assert(table_arg != nullptr);
9989 assert(table_arg->s != nullptr);
9990
9991 return table_arg->s->comment.str;
9992 }
9993
9994 /**
9995 Write a new row
9996
9997 @param[in] buf new row data to write
9998 @return
9999 HA_EXIT_SUCCESS OK
10000 other HA_ERR error code (can be SE-specific)
10001 */
10002 70405715 int ha_rocksdb::write_row(uchar *const buf) {
10003
1/2
✓ Branch 0 taken 70485150 times.
✗ Branch 1 not taken.
70405715 DBUG_ENTER_FUNC();
10004
10005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70485150 times.
70485150 assert(buf != nullptr);
10006
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70485150 times.
70485150 assert(buf == table->record[0]);
10007
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70485150 times.
70485150 assert(m_lock_rows == RDB_LOCK_WRITE);
10008
10009
1/2
✓ Branch 0 taken 70479870 times.
✗ Branch 1 not taken.
70485150 ha_statistic_increment(&System_status_var::ha_write_count);
10010 /*
10011 Note: "buf == table->record[0]" is copied from innodb. I am not aware of
10012 any use cases where this condition is not true.
10013 */
10014
3/4
✓ Branch 0 taken 8227499 times.
✓ Branch 1 taken 62252371 times.
✓ Branch 2 taken 8227968 times.
✗ Branch 3 not taken.
70479870 if (table->next_number_field && buf == table->record[0]) {
10015 int err;
10016
3/4
✓ Branch 0 taken 8242985 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 8242961 times.
8227968 if ((err = update_auto_increment())) {
10017
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 DBUG_RETURN(err);
10018 }
10019 }
10020
10021 // clear cache at beginning of write for INSERT ON DUPLICATE
10022 // we may get multiple write->fail->read->update if there are multiple
10023 // values from INSERT
10024 70494863 m_dup_key_found = false;
10025
10026
2/4
✓ Branch 0 taken 70485266 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70442760 times.
✗ Branch 3 not taken.
70494863 const int rv = update_write_row(nullptr, buf, skip_unique_check());
10027
10028
1/2
✓ Branch 0 taken 70447288 times.
✗ Branch 1 not taken.
70442760 if (rv == 0) {
10029 // Not protected by ddl_manger lock for performance
10030 // reasons. This is an estimate value anyway.
10031
1/2
✓ Branch 0 taken 70447947 times.
✗ Branch 1 not taken.
70447288 inc_table_n_rows();
10032
1/2
✓ Branch 0 taken 70484614 times.
✗ Branch 1 not taken.
70447947 update_table_stats_if_needed();
10033
10034
1/2
✓ Branch 0 taken 70479274 times.
✗ Branch 1 not taken.
70484614 update_row_stats(ROWS_INSERTED);
10035 }
10036
10037
1/2
✓ Branch 0 taken 70494382 times.
✗ Branch 1 not taken.
70474746 DBUG_RETURN(rv);
10038 }
10039
10040 // Increment the number of rows in the table by one.
10041 // This operation is not protected by ddl manager lock.
10042 // The number is estimated.
10043 70443055 void ha_rocksdb::inc_table_n_rows() {
10044
2/2
✓ Branch 0 taken 70416937 times.
✓ Branch 1 taken 26118 times.
70443055 if (!rocksdb_table_stats_use_table_scan) {
10045 70416937 return;
10046 }
10047
10048 26118 uint64 n_rows = m_tbl_def->m_tbl_stats.m_stat_n_rows;
10049
1/2
✓ Branch 0 taken 30372 times.
✗ Branch 1 not taken.
26118 if (n_rows < std::numeric_limits<ulonglong>::max()) {
10050 30372 m_tbl_def->m_tbl_stats.m_stat_n_rows = n_rows + 1;
10051 }
10052 }
10053
10054 // Decrement the number of rows in the table by one.
10055 // This operation is not protected by ddl manager lock.
10056 // The number is estimated.
10057 240972 void ha_rocksdb::dec_table_n_rows() {
10058
1/2
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
240972 if (!rocksdb_table_stats_use_table_scan) {
10059 240972 return;
10060 }
10061
10062 uint64 n_rows = m_tbl_def->m_tbl_stats.m_stat_n_rows;
10063 if (n_rows > 0) {
10064 m_tbl_def->m_tbl_stats.m_stat_n_rows = n_rows - 1;
10065 }
10066 }
10067
10068 /**
10069 Constructing m_last_rowkey (MyRocks key expression) from
10070 before_update|delete image (MySQL row expression).
10071 m_last_rowkey is normally set during lookup phase, such as
10072 rnd_next() and rnd_pos(). With Read Free Replication,
10073 these read functions are skipped and update_rows(), delete_rows() are
10074 called without setting m_last_rowkey. This function sets m_last_rowkey
10075 for Read Free Replication.
10076 */
10077 70884292 void ha_rocksdb::set_last_rowkey(const uchar *const old_data) {
10078 #if defined(ROCKSDB_INCLUDE_RFR) && ROCKSDB_INCLUDE_RFR
10079
4/6
✓ Branch 0 taken 506699 times.
✓ Branch 1 taken 70377593 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 506699 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 70884292 times.
70884292 if (old_data && use_read_free_rpl()) {
10080 const int old_pk_size = m_pk_descr->pack_record(
10081 table, m_pack_buffer, old_data, m_pk_packed_tuple, nullptr, false);
10082 m_last_rowkey.copy((const char *)m_pk_packed_tuple, old_pk_size,
10083 &my_charset_bin);
10084 }
10085 #endif // defined(ROCKSDB_INCLUDE_RFR) && ROCKSDB_INCLUDE_RFR
10086 70884292 }
10087
10088 void ha_rocksdb::set_last_rowkey(const char *str, size_t len) {
10089 m_last_rowkey.copy(str, len, &my_charset_bin);
10090 }
10091
10092 /**
10093 Collect update data for primary key
10094
10095 @param[in, out] row_info hold all data for update row, such as
10096 new row data/old row data
10097 @return
10098 HA_EXIT_SUCCESS OK
10099 other HA_ERR error code (can be SE-specific)
10100 */
10101 70633387 int ha_rocksdb::get_pk_for_update(struct update_row_info *const row_info) {
10102 int size;
10103
10104 /*
10105 Get new row key for any insert, and any update where the pk is not hidden.
10106 Row key for updates with hidden pk is handled below.
10107 */
10108
2/2
✓ Branch 0 taken 70220505 times.
✓ Branch 1 taken 418971 times.
70633387 if (!has_hidden_pk(table)) {
10109 70220505 row_info->hidden_pk_id = 0;
10110
10111 70220505 row_info->new_pk_unpack_info = &m_pk_unpack_info;
10112
10113 140537348 size = m_pk_descr->pack_record(
10114 70223812 table, m_pack_buffer, row_info->new_data, m_pk_packed_tuple,
10115 row_info->new_pk_unpack_info, false, 0, 0, nullptr);
10116
2/2
✓ Branch 0 taken 400949 times.
✓ Branch 1 taken 18022 times.
418971 } else if (row_info->old_data == nullptr) {
10117 400949 row_info->hidden_pk_id = update_hidden_pk_val();
10118 400949 size =
10119 400949 m_pk_descr->pack_hidden_pk(row_info->hidden_pk_id, m_pk_packed_tuple);
10120 } else {
10121 /*
10122 If hidden primary key, rowkey for new record will always be the same as
10123 before
10124 */
10125 18022 size = row_info->old_pk_slice.size();
10126 18022 memcpy(m_pk_packed_tuple, row_info->old_pk_slice.data(), size);
10127 18022 int err = read_hidden_pk_id_from_rowkey(&row_info->hidden_pk_id);
10128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18022 times.
18022 if (err) {
10129 return err;
10130 }
10131 }
10132
10133 70628798 row_info->new_pk_slice =
10134 70735814 rocksdb::Slice((const char *)m_pk_packed_tuple, size);
10135
10136 70628798 return HA_EXIT_SUCCESS;
10137 }
10138
10139 /**
10140 Check the specified primary key value is unique and also lock the row
10141
10142 @param[in] row_info hold all data for update row, such as old row
10143 data and new row data
10144 @param[out] found whether the primary key exists before.
10145 @param[out] pk_changed whether primary key is changed
10146 @return
10147 HA_EXIT_SUCCESS OK
10148 other HA_ERR error code (can be SE-specific)
10149 */
10150 8353626 int ha_rocksdb::check_and_lock_unique_pk(const struct update_row_info &row_info,
10151 bool *const found,
10152 const bool skip_unique_check) {
10153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8353626 times.
8353626 assert(found != nullptr);
10154
10155
4/6
✓ Branch 0 taken 143472 times.
✓ Branch 1 taken 8216714 times.
✓ Branch 2 taken 143472 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 143472 times.
8353626 assert(row_info.old_pk_slice.size() == 0 ||
10156 row_info.new_pk_slice.compare(row_info.old_pk_slice) != 0);
10157
10158 8360186 const bool ignore_pk_unique_check = skip_unique_check;
10159
1/2
✓ Branch 0 taken 8385765 times.
✗ Branch 1 not taken.
8360186 rocksdb::PinnableSlice value;
10160 8385765 rocksdb::PinnableSlice *pslice =
10161
2/2
✓ Branch 0 taken 585 times.
✓ Branch 1 taken 8385180 times.
8385765 m_insert_with_update ? &m_dup_key_retrieved_record : &value;
10162
10163 /*
10164 Perform a read to determine if a duplicate entry exists. For primary
10165 keys, a point lookup will be sufficient.
10166
10167 note: we intentionally don't set options.snapshot here. We want to read
10168 the latest committed data.
10169 */
10170
10171 /*
10172 To prevent race conditions like below, it is necessary to
10173 take a lock for a target row. get_for_update() holds a gap lock if
10174 target key does not exist, so below conditions should never
10175 happen.
10176
10177 1) T1 Get(empty) -> T2 Get(empty) -> T1 Put(insert) -> T1 commit
10178 -> T2 Put(overwrite) -> T2 commit
10179 2) T1 Get(empty) -> T1 Put(insert, not committed yet) -> T2 Get(empty)
10180 -> T2 Put(insert, blocked) -> T1 commit -> T2 commit(overwrite)
10181 */
10182
4/6
✓ Branch 0 taken 8403395 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 96 times.
✓ Branch 3 taken 8403299 times.
✓ Branch 4 taken 8400781 times.
✗ Branch 5 not taken.
8385765 int rc = get_pk_iterator()->get(&row_info.new_pk_slice,
10183 ignore_pk_unique_check ? nullptr : pslice,
10184 m_lock_rows);
10185
10186
3/4
✓ Branch 0 taken 8415369 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
✓ Branch 3 taken 8415311 times.
8400781 if (rc && rc != HA_ERR_KEY_NOT_FOUND) {
10187 58 return rc;
10188 }
10189
10190
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 8400627 times.
8400723 bool key_found = ignore_pk_unique_check ? false : (rc == HA_EXIT_SUCCESS);
10191
10192
6/6
✓ Branch 0 taken 2462 times.
✓ Branch 1 taken 8398261 times.
✓ Branch 2 taken 2451 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 161 times.
✓ Branch 5 taken 2290 times.
8400723 if (key_found && row_info.old_data == nullptr && m_insert_with_update) {
10193 // In INSERT ON DUPLICATE KEY UPDATE ... case, if the insert failed
10194 // due to a duplicate key, remember the last key and skip the check
10195 // next time
10196 161 m_dup_key_found = true;
10197 #ifndef NDEBUG
10198 // save it for sanity checking later
10199
1/2
✓ Branch 0 taken 17060 times.
✗ Branch 1 not taken.
161 m_dup_key_tuple.copy(row_info.new_pk_slice.data(),
10200 row_info.new_pk_slice.size(), &my_charset_bin);
10201 #endif
10202 }
10203
10204 8417622 *found = key_found;
10205
10206 8417622 return HA_EXIT_SUCCESS;
10207 8417680 }
10208
10209 18270 int ha_rocksdb::acquire_prefix_lock(const Rdb_key_def &kd, Rdb_transaction *tx,
10210 const uchar *data) {
10211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18270 times.
18270 assert(kd.is_partial_index());
10212 // Obtain shared lock on prefix.
10213
1/2
✓ Branch 0 taken 18270 times.
✗ Branch 1 not taken.
18270 uint size = kd.pack_record(table, m_pack_buffer, data, m_sk_packed_tuple,
10214 nullptr, false, 0, kd.partial_index_keyparts());
10215 const rocksdb::Slice prefix_slice =
10216 18270 rocksdb::Slice((const char *)m_sk_packed_tuple, size);
10217
10218 const rocksdb::Status s =
10219 18270 tx->get_for_update(kd, prefix_slice, nullptr, false /* exclusive */,
10220
1/2
✓ Branch 0 taken 18270 times.
✗ Branch 1 not taken.
18270 false /* do validate */, false /* no_wait */);
10221
2/4
✓ Branch 0 taken 18270 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18270 times.
18270 if (!s.ok()) {
10222 return tx->set_status_error(table->in_use, s, kd, m_tbl_def);
10223 }
10224
10225 18270 return HA_EXIT_SUCCESS;
10226 18270 }
10227
10228 /**
10229 Check the specified secondary key value is unique and also lock the row
10230
10231 @param[in] key_id key index
10232 @param[in] row_info hold all data for update row, such as old row
10233 data and new row data
10234 @param[out] found whether specified key value exists before.
10235 @return
10236 HA_EXIT_SUCCESS OK
10237 other HA_ERR error code (can be SE-specific)
10238 */
10239 12503856 int ha_rocksdb::check_and_lock_sk(
10240 const uint key_id, const struct update_row_info &row_info,
10241 bool *const found,
10242 const bool skip_unique_check MY_ATTRIBUTE((__unused__))) {
10243
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12503856 times.
12503856 assert(found != nullptr);
10244 12503856 *found = false;
10245
10246 /*
10247 Can skip checking this key if none of the key fields have changed.
10248 */
10249
6/6
✓ Branch 0 taken 287054 times.
✓ Branch 1 taken 12216802 times.
✓ Branch 2 taken 600 times.
✓ Branch 3 taken 286454 times.
✓ Branch 4 taken 600 times.
✓ Branch 5 taken 12503256 times.
12503856 if (row_info.old_data != nullptr && !m_update_scope.is_set(key_id)) {
10250 600 return HA_EXIT_SUCCESS;
10251 }
10252
10253 12503256 KEY *key_info = nullptr;
10254 12503256 uint n_null_fields = 0;
10255 12503256 uint user_defined_key_parts = 1;
10256 12503256 int rc = HA_EXIT_SUCCESS;
10257
10258 12503256 key_info = &table->key_info[key_id];
10259 12503256 user_defined_key_parts = key_info->user_defined_key_parts;
10260 12503256 const Rdb_key_def &kd = *m_key_descr_arr[key_id];
10261
10262
2/2
✓ Branch 0 taken 18270 times.
✓ Branch 1 taken 12484986 times.
12503256 if (kd.is_partial_index()) {
10263 // Obtain shared lock on new/old prefix.
10264
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18270 times.
18270 if (row_info.old_data != nullptr) {
10265 rc = acquire_prefix_lock(kd, row_info.tx, row_info.old_data);
10266 if (rc) return rc;
10267 }
10268
10269
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18270 times.
18270 assert(row_info.new_data != nullptr);
10270
1/2
✓ Branch 0 taken 18270 times.
✗ Branch 1 not taken.
18270 rc = acquire_prefix_lock(kd, row_info.tx, row_info.new_data);
10271
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18270 times.
18270 if (rc) return rc;
10272 }
10273
10274 /*
10275 If there are no uniqueness requirements, there's no need to obtain a
10276 lock for this key.
10277 */
10278
2/2
✓ Branch 0 taken 12490598 times.
✓ Branch 1 taken 12658 times.
12503256 if (!(key_info->flags & HA_NOSAME)) {
10279 12490598 return HA_EXIT_SUCCESS;
10280 }
10281
10282 /*
10283 Calculate the new key for obtaining the lock
10284
10285 For unique secondary indexes, the key used for locking does not
10286 include the extended fields.
10287 */
10288 int size =
10289
1/2
✓ Branch 0 taken 12658 times.
✗ Branch 1 not taken.
12658 kd.pack_record(table, m_pack_buffer, row_info.new_data, m_sk_packed_tuple,
10290 12658 nullptr, false, 0, user_defined_key_parts, &n_null_fields);
10291
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 12514 times.
12658 if (n_null_fields > 0) {
10292 /*
10293 If any fields are marked as NULL this will never match another row as
10294 to NULL never matches anything else including another NULL.
10295 */
10296 144 return HA_EXIT_SUCCESS;
10297 }
10298
10299 const rocksdb::Slice new_slice =
10300 12514 rocksdb::Slice((const char *)m_sk_packed_tuple, size);
10301
10302 /*
10303 Acquire lock on the old key in case of UPDATE
10304 */
10305
2/2
✓ Branch 0 taken 2772 times.
✓ Branch 1 taken 9742 times.
12514 if (row_info.old_data != nullptr) {
10306
1/2
✓ Branch 0 taken 2772 times.
✗ Branch 1 not taken.
2772 size = kd.pack_record(table, m_pack_buffer, row_info.old_data,
10307 m_sk_packed_tuple_old, nullptr, false, 0,
10308 user_defined_key_parts);
10309 const rocksdb::Slice old_slice =
10310 2772 rocksdb::Slice((const char *)m_sk_packed_tuple_old, size);
10311
10312
1/2
✓ Branch 0 taken 2772 times.
✗ Branch 1 not taken.
2772 const rocksdb::Status s = get_for_update(row_info.tx, kd, old_slice);
10313
2/4
✓ Branch 0 taken 2772 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2772 times.
2772 if (!s.ok()) {
10314 return row_info.tx->set_status_error(table->in_use, s, kd, m_tbl_def);
10315 }
10316
10317 /*
10318 If the old and new keys are the same we're done since we've already taken
10319 the lock on the old key
10320 */
10321
3/4
✓ Branch 0 taken 2772 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2415 times.
✓ Branch 3 taken 357 times.
2772 if (!new_slice.compare(old_slice)) {
10322 2415 return HA_EXIT_SUCCESS;
10323 }
10324
2/2
✓ Branch 0 taken 357 times.
✓ Branch 1 taken 2415 times.
2772 }
10325
10326 /*
10327 Perform a read to determine if a duplicate entry exists - since this is
10328 a secondary indexes a range scan is needed.
10329
10330 note: we intentionally don't set options.snapshot here. We want to read
10331 the latest committed data.
10332 */
10333
10334 10099 const bool all_parts_used = (user_defined_key_parts == kd.get_key_parts());
10335
10336 /*
10337 This iterator seems expensive since we need to allocate and free
10338 memory for each unique index.
10339
10340 If this needs to be optimized, for keys without NULL fields, the
10341 extended primary key fields can be migrated to the value portion of the
10342 key. This enables using Get() instead of Seek() as in the primary key
10343 case.
10344
10345 The bloom filter may need to be disabled for this lookup.
10346 */
10347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10099 times.
10099 assert(!m_key_descr_arr[key_id]->is_partial_index());
10348 20198 Rdb_iterator_base iter(ha_thd(), m_key_descr_arr[key_id], m_pk_descr,
10349
2/4
✓ Branch 0 taken 10099 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10099 times.
✗ Branch 3 not taken.
20198 m_tbl_def);
10350
10351 /*
10352 If all_parts_used is true, then PK uniqueness check/lock would already
10353 guarantee SK uniqueness. We could optimize this by calling non-locking
10354 get instead.
10355 */
10356 10099 bool skip_ttl_check = !all_parts_used;
10357
3/4
✓ Branch 0 taken 612 times.
✓ Branch 1 taken 9487 times.
✓ Branch 2 taken 10099 times.
✗ Branch 3 not taken.
10099 rc = iter.get(&new_slice, all_parts_used ? &m_retrieved_record : nullptr,
10358 m_lock_rows, skip_ttl_check);
10359
4/4
✓ Branch 0 taken 3702 times.
✓ Branch 1 taken 6397 times.
✓ Branch 2 taken 90 times.
✓ Branch 3 taken 3612 times.
10099 if (rc && rc != HA_ERR_KEY_NOT_FOUND) {
10360 90 return rc;
10361 }
10362
10363
2/2
✓ Branch 0 taken 9397 times.
✓ Branch 1 taken 612 times.
10009 if (!all_parts_used) {
10364
1/2
✓ Branch 0 taken 9397 times.
✗ Branch 1 not taken.
9397 rc = iter.seek(HA_READ_KEY_EXACT, new_slice, false /* full_key_match */,
10365 new_slice, true /* read current */);
10366
10367
3/4
✓ Branch 0 taken 8788 times.
✓ Branch 1 taken 609 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8788 times.
9397 if (rc && rc != HA_ERR_END_OF_FILE) {
10368 return rc;
10369 }
10370 }
10371
10372 10009 *found = (rc == HA_EXIT_SUCCESS);
10373
10374 10009 rc = HA_EXIT_SUCCESS;
10375
4/4
✓ Branch 0 taken 609 times.
✓ Branch 1 taken 9400 times.
✓ Branch 2 taken 216 times.
✓ Branch 3 taken 393 times.
10009 if (*found && m_insert_with_update) {
10376
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
✓ Branch 2 taken 216 times.
✗ Branch 3 not taken.
216 const rocksdb::Slice &rkey = all_parts_used ? new_slice : iter.key();
10377 uint pk_size =
10378
1/2
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
216 kd.get_primary_key_tuple(*m_pk_descr, &rkey, m_pk_packed_tuple);
10379
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 if (pk_size == RDB_INVALID_KEY_LEN) {
10380 rc = HA_ERR_ROCKSDB_CORRUPT_DATA;
10381 } else {
10382 216 m_dup_key_found = true;
10383
1/2
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
216 m_last_rowkey.copy((const char *)m_pk_packed_tuple, pk_size,
10384 &my_charset_bin);
10385 #ifndef NDEBUG
10386 // save it for sanity checking later
10387
1/2
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
216 m_dup_key_tuple.copy(rkey.data(), rkey.size(), &my_charset_bin);
10388 #endif
10389 }
10390 }
10391
10392 10009 return rc;
10393 10099 }
10394
10395 /**
10396 Enumerate all keys to check their uniquess and also lock it
10397
10398 @param[in] row_info hold all data for update row, such as old row
10399 data and new row data
10400 @param[out] pk_changed whether primary key is changed
10401 @return
10402 HA_EXIT_SUCCESS OK
10403 other HA_ERR error code (can be SE-specific)
10404 */
10405 8466778 int ha_rocksdb::check_uniqueness_and_lock(
10406 const struct update_row_info &row_info, bool pk_changed,
10407 bool skip_unique_check) {
10408 8466778 Rdb_transaction *const tx = get_or_create_tx(ha_thd());
10409 8587851 tx->acquire_snapshot(false);
10410
10411 /*
10412 Go through each index and determine if the index has uniqueness
10413 requirements. If it does, then try to obtain a row lock on the new values.
10414 Once all locks have been obtained, then perform the changes needed to
10415 update/insert the row.
10416 */
10417
2/2
✓ Branch 0 taken 20992503 times.
✓ Branch 1 taken 8575494 times.
29567997 for (uint key_id = 0; key_id < m_tbl_def->m_key_count; key_id++) {
10418 bool found;
10419 int rc;
10420
10421
4/6
✓ Branch 0 taken 21000745 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 21000742 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
20992503 DBUG_EXECUTE_IF("rocksdb_blob_crash",
10422 DBUG_SET("+d,rocksdb_check_uniqueness"););
10423
3/4
✓ Branch 0 taken 20998607 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8498002 times.
✓ Branch 3 taken 12500605 times.
21000745 if (is_pk(key_id, table, m_tbl_def)) {
10424
6/6
✓ Branch 0 taken 265727 times.
✓ Branch 1 taken 8236656 times.
✓ Branch 2 taken 122255 times.
✓ Branch 3 taken 143472 times.
✓ Branch 4 taken 122255 times.
✓ Branch 5 taken 8380128 times.
8498002 if (row_info.old_pk_slice.size() > 0 && !pk_changed) {
10425 122255 found = false;
10426 122255 rc = HA_EXIT_SUCCESS;
10427 } else {
10428
1/2
✓ Branch 0 taken 8398126 times.
✗ Branch 1 not taken.
8380128 rc = check_and_lock_unique_pk(row_info, &found, skip_unique_check);
10429
3/6
✓ Branch 0 taken 8403215 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8442235 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8476294 times.
✗ Branch 5 not taken.
8398126 DEBUG_SYNC(ha_thd(), "rocksdb.after_unique_pk_check");
10430 }
10431 } else {
10432
1/2
✓ Branch 0 taken 12503856 times.
✗ Branch 1 not taken.
12500605 rc = check_and_lock_sk(key_id, row_info, &found, skip_unique_check);
10433
3/6
✓ Branch 0 taken 12503856 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12503856 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12503856 times.
✗ Branch 5 not taken.
12503856 DEBUG_SYNC(ha_thd(), "rocksdb.after_unique_sk_check");
10434 }
10435
3/6
✓ Branch 0 taken 21095699 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 21095696 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
21095721 DBUG_EXECUTE_IF("rocksdb_blob_crash",
10436 DBUG_SET("-d,rocksdb_check_uniqueness"););
10437
10438
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 21078572 times.
21078720 if (rc != HA_EXIT_SUCCESS) {
10439 3219 return rc;
10440 }
10441
10442
2/2
✓ Branch 0 taken 3071 times.
✓ Branch 1 taken 21075501 times.
21078572 if (found) {
10443 /* There is a row with this key already, so error out. */
10444 3071 errkey = key_id;
10445 3071 m_dupp_errkey = errkey;
10446
10447 3071 return HA_ERR_FOUND_DUPP_KEY;
10448 }
10449 }
10450
10451 8575494 return HA_EXIT_SUCCESS;
10452 }
10453
10454 68234657 int ha_rocksdb::bulk_load_key(Rdb_transaction *const tx, const Rdb_key_def &kd,
10455 const rocksdb::Slice &key,
10456 const rocksdb::Slice &value, bool sort) {
10457
1/2
✓ Branch 0 taken 68234657 times.
✗ Branch 1 not taken.
68234657 DBUG_ENTER_FUNC();
10458 int res;
10459
1/2
✓ Branch 0 taken 68234657 times.
✗ Branch 1 not taken.
68234657 THD *thd = ha_thd();
10460
3/6
✓ Branch 0 taken 68234657 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 68234657 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 68234657 times.
68234657 if (thd && thd->killed) {
10461 DBUG_RETURN(HA_ERR_QUERY_INTERRUPTED);
10462 }
10463
10464 68234657 rocksdb::ColumnFamilyHandle *cf = kd.get_cf();
10465
10466 // In the case of unsorted inserts, m_sst_info allocated here is not
10467 // used to store the keys. It is still used to indicate when tables
10468 // are switched.
10469
6/6
✓ Branch 0 taken 68234104 times.
✓ Branch 1 taken 553 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 68234068 times.
✓ Branch 4 taken 589 times.
✓ Branch 5 taken 68234068 times.
68234657 if (m_sst_info == nullptr || m_sst_info->is_done()) {
10470
2/4
✓ Branch 0 taken 589 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 589 times.
✗ Branch 3 not taken.
1178 m_sst_info.reset(new Rdb_sst_info(rdb, m_table_handler->m_table_name,
10471 589 kd.get_name(), cf, *rocksdb_db_options,
10472
4/8
✓ Branch 0 taken 589 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 589 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 589 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 589 times.
✗ Branch 7 not taken.
589 THDVAR(ha_thd(), trace_sst_api)));
10473
1/2
✓ Branch 0 taken 589 times.
✗ Branch 1 not taken.
589 res = tx->start_bulk_load(this, m_sst_info);
10474
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 586 times.
589 if (res != HA_EXIT_SUCCESS) {
10475
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(res);
10476 }
10477 }
10478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68234654 times.
68234654 assert(m_sst_info);
10479
10480
2/2
✓ Branch 0 taken 24080865 times.
✓ Branch 1 taken 44153789 times.
68234654 if (sort) {
10481 Rdb_index_merge *key_merge;
10482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24080865 times.
24080865 assert(cf != nullptr);
10483
10484
2/4
✓ Branch 0 taken 24080865 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24080865 times.
✗ Branch 3 not taken.
24080865 res = tx->get_key_merge(kd.get_gl_index_id(), cf, &key_merge);
10485
1/2
✓ Branch 0 taken 24080865 times.
✗ Branch 1 not taken.
24080865 if (res == HA_EXIT_SUCCESS) {
10486
1/2
✓ Branch 0 taken 24080865 times.
✗ Branch 1 not taken.
24080865 res = key_merge->add(key, value);
10487 }
10488 } else {
10489
1/2
✓ Branch 0 taken 44153789 times.
✗ Branch 1 not taken.
44153789 res = m_sst_info->put(key, value);
10490 }
10491
10492
1/2
✓ Branch 0 taken 68234654 times.
✗ Branch 1 not taken.
68234654 DBUG_RETURN(res);
10493 }
10494
10495 131845 int ha_rocksdb::finalize_bulk_load(bool print_client_error) {
10496
1/2
✓ Branch 0 taken 131845 times.
✗ Branch 1 not taken.
131845 DBUG_ENTER_FUNC();
10497
10498 131845 int res = HA_EXIT_SUCCESS;
10499
10500 /* Skip if there are no possible ongoing bulk loads */
10501
2/2
✓ Branch 0 taken 538 times.
✓ Branch 1 taken 131307 times.
131845 if (m_sst_info) {
10502
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 16 times.
538 if (m_sst_info->is_done()) {
10503 522 m_sst_info.reset();
10504
1/2
✓ Branch 0 taken 522 times.
✗ Branch 1 not taken.
522 DBUG_RETURN(res);
10505 }
10506
10507 16 Rdb_sst_info::Rdb_sst_commit_info commit_info;
10508
10509 // Wrap up the current work in m_sst_info and get ready to commit
10510 // This transfer the responsibility of commit over to commit_info
10511
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 res = m_sst_info->finish(&commit_info, print_client_error);
10512
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (res == 0) {
10513 // Make sure we have work to do - under race condition we could lose
10514 // to another thread and end up with no work
10515
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 9 times.
16 if (commit_info.has_work()) {
10516 7 rocksdb::IngestExternalFileOptions opts;
10517 7 opts.move_files = true;
10518 7 opts.snapshot_consistency = false;
10519 7 opts.allow_global_seqno = false;
10520 7 opts.allow_blocking_flush = false;
10521
10522 7 const rocksdb::Status s = rdb->IngestExternalFile(
10523
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 commit_info.get_cf(), commit_info.get_committed_files(), opts);
10524
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 if (!s.ok()) {
10525 if (print_client_error) {
10526 Rdb_sst_info::report_error_msg(s, nullptr);
10527 }
10528 res = HA_ERR_ROCKSDB_BULK_LOAD;
10529 } else {
10530 // Mark the list of SST files as committed, otherwise they'll get
10531 // cleaned up when commit_info destructs
10532 7 commit_info.commit();
10533 }
10534 7 }
10535 }
10536 16 m_sst_info.reset();
10537 16 }
10538
1/2
✓ Branch 0 taken 131323 times.
✗ Branch 1 not taken.
131323 DBUG_RETURN(res);
10539 }
10540
10541 /**
10542 Update an existing primary key record or write a new primary key record
10543
10544 @param[in] kd the primary key is being update/write
10545 @param[in] update_row_info hold all row data, such as old row data and
10546 new row data
10547 @param[in] pk_changed whether primary key is changed
10548 @return
10549 HA_EXIT_SUCCESS OK
10550 Other HA_ERR error code (can be SE-specific)
10551 */
10552 70672862 int ha_rocksdb::update_write_pk(const Rdb_key_def &kd,
10553 const struct update_row_info &row_info,
10554 const bool pk_changed) {
10555 70672862 const uint key_id = kd.get_keyno();
10556
1/2
✓ Branch 0 taken 70678909 times.
✗ Branch 1 not taken.
70670840 const bool hidden_pk = is_hidden_pk(key_id, table, m_tbl_def);
10557
10558 /*
10559 If the PK has changed, or if this PK uses single deletes and this is an
10560 update, the old key needs to be deleted. In the single delete case, it
10561 might be possible to have this sequence of keys: PUT(X), PUT(X), SD(X),
10562 resulting in the first PUT(X) showing up.
10563 */
10564
8/8
✓ Branch 0 taken 70261802 times.
✓ Branch 1 taken 417107 times.
✓ Branch 2 taken 70120014 times.
✓ Branch 3 taken 141788 times.
✓ Branch 4 taken 98662 times.
✓ Branch 5 taken 70022359 times.
✓ Branch 6 taken 143428 times.
✓ Branch 7 taken 70542041 times.
70783124 if (!hidden_pk && (pk_changed || ((row_info.old_pk_slice.size() > 0) &&
10565
3/4
✓ Branch 0 taken 104215 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1640 times.
✓ Branch 3 taken 102575 times.
98662 can_use_single_delete(key_id)))) {
10566 const rocksdb::Status s = delete_or_singledelete(
10567
1/2
✓ Branch 0 taken 143428 times.
✗ Branch 1 not taken.
143428 key_id, row_info.tx, kd.get_cf(), row_info.old_pk_slice);
10568
2/4
✓ Branch 0 taken 143428 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 143428 times.
143428 if (!s.ok()) {
10569 return row_info.tx->set_status_error(table->in_use, s, kd, m_tbl_def);
10570 }
10571
1/2
✓ Branch 0 taken 143428 times.
✗ Branch 1 not taken.
143428 }
10572
10573
2/2
✓ Branch 0 taken 8181541 times.
✓ Branch 1 taken 62503928 times.
70685469 if (table->found_next_number_field) {
10574
1/2
✓ Branch 0 taken 8150014 times.
✗ Branch 1 not taken.
8181541 update_auto_incr_val_from_field();
10575 }
10576
10577 70653942 int rc = HA_EXIT_SUCCESS;
10578 70653942 rocksdb::Slice value_slice;
10579 /* Prepare the new record to be written into RocksDB */
10580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70654776 times.
141306138 if ((rc = m_converter->encode_value_slice(
10581 70636038 m_pk_descr, row_info.new_pk_slice, row_info.new_pk_unpack_info,
10582
1/2
✓ Branch 0 taken 70654776 times.
✗ Branch 1 not taken.
70666291 !row_info.old_pk_slice.empty(), should_store_row_debug_checksums(),
10583 m_ttl_bytes, &m_ttl_bytes_updated, &value_slice))) {
10584 return rc;
10585 }
10586
10587 70654776 const auto cf = m_pk_descr->get_cf();
10588
6/8
✓ Branch 0 taken 70679528 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70711384 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 62153954 times.
✓ Branch 5 taken 8557430 times.
✓ Branch 6 taken 62153954 times.
✓ Branch 7 taken 8535071 times.
132811123 if (rocksdb_enable_bulk_load_api && THDVAR(table->in_use, bulk_load) &&
10589
1/2
✓ Branch 0 taken 62153954 times.
✗ Branch 1 not taken.
62153954 !hidden_pk) {
10590 /*
10591 Write the primary key directly to an SST file using an SstFileWriter
10592 */
10593 62153954 rc = bulk_load_key(row_info.tx, kd, row_info.new_pk_slice, value_slice,
10594
2/4
✓ Branch 0 taken 62153954 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62153954 times.
✗ Branch 3 not taken.
62153954 THDVAR(table->in_use, bulk_load_allow_unsorted));
10595
4/4
✓ Branch 0 taken 8533122 times.
✓ Branch 1 taken 1949 times.
✓ Branch 2 taken 1095870 times.
✓ Branch 3 taken 7437252 times.
8535071 } else if (row_info.skip_unique_check || row_info.tx->m_ddl_transaction) {
10596 /*
10597 It is responsibility of the user to make sure that the data being
10598 inserted doesn't violate any unique keys.
10599 */
10600
2/4
✓ Branch 0 taken 1078734 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1078734 times.
✗ Branch 3 not taken.
1097819 row_info.tx->get_indexed_write_batch()->Put(cf, row_info.new_pk_slice,
10601 value_slice);
10602 } else {
10603
2/4
✓ Branch 0 taken 7468812 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7504333 times.
✗ Branch 3 not taken.
7437252 const bool assume_tracked = can_assume_tracked(ha_thd());
10604 7504333 const auto s = row_info.tx->put(cf, row_info.new_pk_slice, value_slice,
10605
1/2
✓ Branch 0 taken 7478555 times.
✗ Branch 1 not taken.
7504333 assume_tracked);
10606
3/4
✓ Branch 0 taken 7491984 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 7491982 times.
7478555 if (!s.ok()) {
10607
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (s.IsBusy()) {
10608 errkey = table->s->primary_key;
10609 m_dupp_errkey = errkey;
10610 rc = HA_ERR_FOUND_DUPP_KEY;
10611 } else {
10612
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 rc = row_info.tx->set_status_error(table->in_use, s, *m_pk_descr,
10613 2 m_tbl_def);
10614 }
10615 }
10616 7491984 }
10617
10618 70728315 return rc;
10619 }
10620
10621 /**
10622 update an existing secondary key record or write a new secondary key record
10623
10624 @param[in] table_arg Table we're working on
10625 @param[in] kd The secondary key being update/write
10626 @param[in] row_info data structure contains old row data and new row data
10627 @param[in] bulk_load_sk whether support bulk load. Currently it is only
10628 support for write
10629 @return
10630 HA_EXIT_SUCCESS OK
10631 Other HA_ERR error code (can be SE-specific)
10632 */
10633 53054461 int ha_rocksdb::update_write_sk(const TABLE *const table_arg,
10634 const Rdb_key_def &kd,
10635 const struct update_row_info &row_info,
10636 const bool bulk_load_sk) {
10637 int new_packed_size;
10638 int old_packed_size;
10639 53054461 int rc = HA_EXIT_SUCCESS;
10640
10641 53054461 rocksdb::Slice new_key_slice;
10642 53054462 rocksdb::Slice new_value_slice;
10643 53054462 rocksdb::Slice old_key_slice;
10644
10645 53054462 const uint key_id = kd.get_keyno();
10646 /*
10647 Can skip updating this key if none of the key fields have changed and, if
10648 this table has TTL, the TTL timestamp has not changed.
10649 */
10650
6/6
✓ Branch 0 taken 286940 times.
✓ Branch 1 taken 52767522 times.
✓ Branch 2 taken 600 times.
✓ Branch 3 taken 286340 times.
✓ Branch 4 taken 600 times.
✓ Branch 5 taken 53053862 times.
53055062 if (row_info.old_data != nullptr && !m_update_scope.is_set(key_id) &&
10651
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 600 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
600 (!kd.has_ttl() || !m_ttl_bytes_updated)) {
10652 600 return HA_EXIT_SUCCESS;
10653 }
10654
10655 53053862 bool store_row_debug_checksums = should_store_row_debug_checksums();
10656 53053862 new_packed_size =
10657 106107724 kd.pack_record(table_arg, m_pack_buffer, row_info.new_data,
10658 m_sk_packed_tuple, &m_sk_tails, store_row_debug_checksums,
10659
1/2
✓ Branch 0 taken 53053862 times.
✗ Branch 1 not taken.
53053862 row_info.hidden_pk_id, 0, nullptr, m_ttl_bytes);
10660
10661
2/2
✓ Branch 0 taken 286340 times.
✓ Branch 1 taken 52767522 times.
53053862 if (row_info.old_data != nullptr) {
10662 // The old value
10663 572680 old_packed_size = kd.pack_record(
10664 286340 table_arg, m_pack_buffer, row_info.old_data, m_sk_packed_tuple_old,
10665 286340 &m_sk_tails_old, store_row_debug_checksums, row_info.hidden_pk_id, 0,
10666
1/2
✓ Branch 0 taken 286340 times.
✗ Branch 1 not taken.
286340 nullptr, m_ttl_bytes);
10667
10668 /*
10669 Check if we are going to write the same value. This can happen when
10670 one does
10671 UPDATE tbl SET col='foo'
10672 and we are looking at the row that already has col='foo'.
10673
10674 We also need to compare the unpack info. Suppose, the collation is
10675 case-insensitive, and unpack info contains information about whether
10676 the letters were uppercase and lowercase. Then, both 'foo' and 'FOO'
10677 will have the same key value, but different data in unpack_info.
10678
10679 (note: anyone changing bytewise_compare should take this code into
10680 account)
10681 */
10682
2/2
✓ Branch 0 taken 286330 times.
✓ Branch 1 taken 1 times.
286331 if (old_packed_size == new_packed_size &&
10683 286331 m_sk_tails_old.get_current_pos() == m_sk_tails.get_current_pos() &&
10684
4/4
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 286210 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 60 times.
286330 !(kd.has_ttl() && m_ttl_bytes_updated) &&
10685
2/2
✓ Branch 0 taken 67390 times.
✓ Branch 1 taken 218880 times.
286270 memcmp(m_sk_packed_tuple_old, m_sk_packed_tuple, old_packed_size) ==
10686
4/4
✓ Branch 0 taken 286331 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 67390 times.
✓ Branch 3 taken 218950 times.
572671 0 &&
10687
1/2
✓ Branch 0 taken 67390 times.
✗ Branch 1 not taken.
67390 memcmp(m_sk_tails_old.ptr(), m_sk_tails.ptr(),
10688 m_sk_tails.get_current_pos()) == 0) {
10689 67390 return HA_EXIT_SUCCESS;
10690 }
10691
10692 /*
10693 Deleting entries from secondary index should skip locking, but
10694 be visible to the transaction.
10695 (also note that DDL statements do not delete rows, so this is not a DDL
10696 statement)
10697 */
10698 437900 old_key_slice = rocksdb::Slice(
10699 218950 reinterpret_cast<const char *>(m_sk_packed_tuple_old), old_packed_size);
10700
10701 // TODO(mung) - If the new_data and old_data below to the same partial index
10702 // group (ie. have the same prefix), we can make use of the read below to
10703 // determine whether to issue SingleDelete or not.
10704 //
10705 // Currently we unconditionally issue SingleDelete, meaning that it is
10706 // possible for SD to be compacted out without meeting any Puts. This bumps
10707 // the num_single_delete_fallthrough counter in rocksdb, but is otherwise
10708 // fine as the SD markers just get compacted out. We will have to revisit
10709 // this if we want stronger consistency checks though.
10710
2/4
✓ Branch 0 taken 218950 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 218950 times.
✗ Branch 3 not taken.
218950 row_info.tx->get_indexed_write_batch()->SingleDelete(kd.get_cf(),
10711 old_key_slice);
10712 }
10713
10714
6/6
✓ Branch 0 taken 18930 times.
✓ Branch 1 taken 52967541 times.
✓ Branch 2 taken 18270 times.
✓ Branch 3 taken 660 times.
✓ Branch 4 taken 18270 times.
✓ Branch 5 taken 52968201 times.
52986472 if (kd.is_partial_index() && !bulk_load_sk) {
10715 // TODO(mung) - We've already calculated prefix len when locking. If we
10716 // cache that value, we can avoid recalculating here.
10717
1/2
✓ Branch 0 taken 18270 times.
✗ Branch 1 not taken.
18270 int size = kd.pack_record(table_arg, m_pack_buffer, row_info.new_data,
10718 m_sk_packed_tuple, nullptr, false, 0,
10719 18270 kd.partial_index_keyparts());
10720 const rocksdb::Slice prefix_slice =
10721 18270 rocksdb::Slice((const char *)m_sk_packed_tuple, size);
10722
10723
1/2
✓ Branch 0 taken 18270 times.
✗ Branch 1 not taken.
18270 rocksdb::PinnableSlice value;
10724 18270 const rocksdb::Status s = row_info.tx->get_for_update(
10725 kd, prefix_slice, &value, false /* exclusive */,
10726
1/2
✓ Branch 0 taken 18270 times.
✗ Branch 1 not taken.
18270 false /* do validate */, false /* no_wait */);
10727
5/10
✓ Branch 0 taken 18270 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18270 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18270 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 18270 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 18270 times.
18270 if (!s.ok() && !s.IsNotFound()) {
10728 return row_info.tx->set_status_error(table_arg->in_use, s, kd, m_tbl_def);
10729 }
10730
10731 // We can skip updating the index, if the prefix is not materialized.
10732
2/4
✓ Branch 0 taken 18270 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18270 times.
✗ Branch 3 not taken.
18270 if (s.IsNotFound()) {
10733 18270 return 0;
10734 }
10735
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18270 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18270 times.
36540 }
10736
10737 105936402 new_key_slice = rocksdb::Slice(
10738 52968201 reinterpret_cast<const char *>(m_sk_packed_tuple), new_packed_size);
10739 52968202 new_value_slice =
10740 52968201 rocksdb::Slice(reinterpret_cast<const char *>(m_sk_tails.ptr()),
10741 m_sk_tails.get_current_pos());
10742
10743
3/4
✓ Branch 0 taken 1501500 times.
✓ Branch 1 taken 51466702 times.
✓ Branch 2 taken 1501500 times.
✗ Branch 3 not taken.
52968202 if (bulk_load_sk && row_info.old_data == nullptr) {
10744
1/2
✓ Branch 0 taken 1501500 times.
✗ Branch 1 not taken.
1501500 rc = bulk_load_key(row_info.tx, kd, new_key_slice, new_value_slice, true);
10745 } else {
10746
2/4
✓ Branch 0 taken 51466702 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51466702 times.
✗ Branch 3 not taken.
51466702 row_info.tx->get_indexed_write_batch()->Put(kd.get_cf(), new_key_slice,
10747 new_value_slice);
10748 }
10749
10750 52968202 return rc;
10751 }
10752
10753 /**
10754 Update existing indexes(PK/SKs) or write new indexes(PK/SKs)
10755
10756 @param[in] row_info hold all row data, such as old key/new key
10757 @param[in] pk_changed whether primary key is changed
10758 @return
10759 HA_EXIT_SUCCESS OK
10760 Other HA_ERR error code (can be SE-specific)
10761 */
10762 70707933 int ha_rocksdb::update_write_indexes(const struct update_row_info &row_info,
10763 const bool pk_changed) {
10764 int rc;
10765 bool bulk_load_sk;
10766
10767 // The PK must be updated first to pull out the TTL value.
10768 70707933 rc = update_write_pk(*m_pk_descr, row_info, pk_changed);
10769
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 70710628 times.
70710639 if (rc != HA_EXIT_SUCCESS) {
10770 11 return rc;
10771 }
10772
10773 // Update the remaining indexes. Allow bulk loading only if
10774 // allow_sk is enabled
10775 141466136 bulk_load_sk = rocksdb_enable_bulk_load_api &&
10776
3/4
✓ Branch 0 taken 70715528 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62146203 times.
✓ Branch 3 taken 8585444 times.
132864573 THDVAR(table->in_use, bulk_load) &&
10777
2/2
✓ Branch 0 taken 1500750 times.
✓ Branch 1 taken 60653195 times.
62146203 THDVAR(table->in_use, bulk_load_allow_sk);
10778
2/2
✓ Branch 0 taken 123788279 times.
✓ Branch 1 taken 70729145 times.
194517424 for (uint key_id = 0; key_id < m_tbl_def->m_key_count; key_id++) {
10779
2/2
✓ Branch 0 taken 70725769 times.
✓ Branch 1 taken 53053427 times.
123788279 if (is_pk(key_id, table, m_tbl_def)) {
10780 70725769 continue;
10781 }
10782
10783 53053427 rc = update_write_sk(table, *m_key_descr_arr[key_id], row_info,
10784 bulk_load_sk);
10785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53057166 times.
53057166 if (rc != HA_EXIT_SUCCESS) {
10786 return rc;
10787 }
10788 }
10789
10790 70729145 return HA_EXIT_SUCCESS;
10791 }
10792
10793 /**
10794 Update an existing row or write a new row
10795
10796 @param[in] old_data nullptr for write, non-null for update
10797 @param[in] new_data non-null for write/update
10798 @param[in] skip_unique_check whether to check uniqueness
10799 @return
10800 HA_EXIT_SUCCESS OK
10801 Other HA_ERR error code (can be SE-specific)
10802 */
10803 70672411 int ha_rocksdb::update_write_row(const uchar *const old_data,
10804 const uchar *const new_data,
10805 const bool skip_unique_check) {
10806
1/2
✓ Branch 0 taken 70753620 times.
✗ Branch 1 not taken.
70672411 DBUG_ENTER_FUNC();
10807
10808
1/2
✓ Branch 0 taken 70725693 times.
✗ Branch 1 not taken.
70753620 THD *thd = ha_thd();
10809
6/6
✓ Branch 0 taken 70723735 times.
✓ Branch 1 taken 1958 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 70726156 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 70728114 times.
70725693 if (thd && thd->killed) {
10810
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 DBUG_RETURN(HA_ERR_QUERY_INTERRUPTED);
10811 }
10812
10813 70728114 bool pk_changed = false;
10814 70728114 struct update_row_info row_info;
10815
10816 70666447 row_info.old_data = old_data;
10817 70666447 row_info.new_data = new_data;
10818 70666447 row_info.skip_unique_check = skip_unique_check;
10819 70666447 row_info.new_pk_unpack_info = nullptr;
10820
1/2
✓ Branch 0 taken 70664031 times.
✗ Branch 1 not taken.
70666447 set_last_rowkey(old_data);
10821
10822
1/2
✓ Branch 0 taken 70640660 times.
✗ Branch 1 not taken.
70664031 row_info.tx = get_or_create_tx(table->in_use);
10823
10824
2/2
✓ Branch 0 taken 265727 times.
✓ Branch 1 taken 70374933 times.
70640660 if (old_data != nullptr) {
10825 265727 row_info.old_pk_slice =
10826 265727 rocksdb::Slice(m_last_rowkey.ptr(), m_last_rowkey.length());
10827
10828 /* Determine which indexes need updating. */
10829
1/2
✓ Branch 0 taken 265727 times.
✗ Branch 1 not taken.
265727 calc_updated_indexes();
10830 }
10831
10832 /*
10833 Get the new row key into row_info.new_pk_slice
10834 */
10835
1/2
✓ Branch 0 taken 70626829 times.
✗ Branch 1 not taken.
70640660 int rc = get_pk_for_update(&row_info);
10836
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70626829 times.
70626829 if (rc != HA_EXIT_SUCCESS) {
10837 DBUG_RETURN(rc);
10838 }
10839
10840 /*
10841 For UPDATEs, if the key has changed, we need to obtain a lock. INSERTs
10842 always require locking.
10843 */
10844
2/2
✓ Branch 0 taken 265727 times.
✓ Branch 1 taken 70363725 times.
70626829 if (row_info.old_pk_slice.size() > 0) {
10845
1/2
✓ Branch 0 taken 265727 times.
✗ Branch 1 not taken.
265727 pk_changed = row_info.new_pk_slice.compare(row_info.old_pk_slice) != 0;
10846 }
10847
10848 // Case: We skip both unique checks and rows locks only when bulk load is
10849 // enabled or if rocksdb_skip_locks_if_skip_unique_check is ON
10850
5/6
✓ Branch 0 taken 70647779 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8499064 times.
✓ Branch 3 taken 62148715 times.
✓ Branch 4 taken 8499822 times.
✓ Branch 5 taken 62147957 times.
79128516 if (!THDVAR(table->in_use, bulk_load) &&
10851
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 8499058 times.
✓ Branch 2 taken 3514 times.
✗ Branch 3 not taken.
8499064 (!rocksdb_skip_locks_if_skip_unique_check || !skip_unique_check)) {
10852 /*
10853 Check to see if we are going to have failures because of unique
10854 keys. Also lock the appropriate key values.
10855 */
10856
1/2
✓ Branch 0 taken 8552663 times.
✗ Branch 1 not taken.
8499822 rc = check_uniqueness_and_lock(row_info, pk_changed, skip_unique_check);
10857
2/2
✓ Branch 0 taken 3219 times.
✓ Branch 1 taken 8549444 times.
8552663 if (rc != HA_EXIT_SUCCESS) {
10858
1/2
✓ Branch 0 taken 3219 times.
✗ Branch 1 not taken.
3219 DBUG_RETURN(rc);
10859 }
10860 }
10861
10862
3/6
✓ Branch 0 taken 70725956 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70748248 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 70755706 times.
✗ Branch 5 not taken.
70697401 DEBUG_SYNC(ha_thd(), "rocksdb.update_write_row_after_unique_check");
10863
10864 /*
10865 At this point, all locks have been obtained, and all checks for duplicate
10866 keys have been performed. No further errors can be allowed to occur from
10867 here because updates to the transaction will be made and those updates
10868 cannot be easily removed without rolling back the entire transaction.
10869 */
10870
1/2
✓ Branch 0 taken 70727571 times.
✗ Branch 1 not taken.
70745937 rc = update_write_indexes(row_info, pk_changed);
10871
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 70727560 times.
70727571 if (rc != HA_EXIT_SUCCESS) {
10872
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 DBUG_RETURN(rc);
10873 }
10874
10875
1/2
✓ Branch 0 taken 70718276 times.
✗ Branch 1 not taken.
70727560 row_info.tx->log_table_write_op(m_tbl_def);
10876
10877
2/4
✓ Branch 0 taken 70722247 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 70722247 times.
70718276 if (do_bulk_commit(row_info.tx)) {
10878 DBUG_RETURN(HA_ERR_ROCKSDB_BULK_LOAD);
10879 }
10880
10881
1/2
✓ Branch 0 taken 70744466 times.
✗ Branch 1 not taken.
70722247 DBUG_RETURN(HA_EXIT_SUCCESS);
10882 }
10883
10884 /*
10885 Setting iterator upper/lower bounds for Seek/SeekForPrev.
10886 This makes RocksDB to avoid scanning tombstones outside of
10887 the given key ranges, when prefix_same_as_start=true was not passed
10888 (when prefix bloom filter can not be used).
10889 Inversing upper/lower bound is necessary on reverse order CF.
10890 This covers HA_READ_PREFIX_LAST* case as well. For example,
10891 if given query eq condition was 12 bytes and condition was
10892 0x0000b3eb003f65c5e78858b8, and if doing HA_READ_PREFIX_LAST,
10893 eq_cond_len was 11 (see calc_eq_cond_len() for details).
10894 If the index was reverse order, upper bound would be
10895 0x0000b3eb003f65c5e78857, and lower bound would be
10896 0x0000b3eb003f65c5e78859. These cover given eq condition range.
10897 */
10898 218892 static void setup_iterator_bounds(const Rdb_key_def &kd,
10899 const rocksdb::Slice &eq_cond,
10900 size_t bound_len, uchar *const lower_bound,
10901 uchar *const upper_bound,
10902 rocksdb::Slice *lower_bound_slice,
10903 rocksdb::Slice *upper_bound_slice) {
10904 // If eq_cond is shorter than Rdb_key_def::INDEX_NUMBER_SIZE, we should be
10905 // able to get better bounds just by using index id directly.
10906
2/2
✓ Branch 0 taken 40985 times.
✓ Branch 1 taken 177907 times.
218892 if (eq_cond.size() <= Rdb_key_def::INDEX_NUMBER_SIZE) {
10907
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40985 times.
40985 assert(bound_len == Rdb_key_def::INDEX_NUMBER_SIZE);
10908 uint size;
10909 40985 kd.get_infimum_key(lower_bound, &size);
10910
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40985 times.
40985 assert(size == Rdb_key_def::INDEX_NUMBER_SIZE);
10911 40985 kd.get_supremum_key(upper_bound, &size);
10912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40985 times.
40985 assert(size == Rdb_key_def::INDEX_NUMBER_SIZE);
10913 } else {
10914
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 177907 times.
177907 assert(bound_len <= eq_cond.size());
10915 177907 memcpy(upper_bound, eq_cond.data(), bound_len);
10916 177907 kd.successor(upper_bound, bound_len);
10917 177907 memcpy(lower_bound, eq_cond.data(), bound_len);
10918 177907 kd.predecessor(lower_bound, bound_len);
10919 }
10920
10921
2/2
✓ Branch 0 taken 62086 times.
✓ Branch 1 taken 156806 times.
218892 if (kd.m_is_reverse_cf) {
10922 62086 *upper_bound_slice = rocksdb::Slice((const char *)lower_bound, bound_len);
10923 62086 *lower_bound_slice = rocksdb::Slice((const char *)upper_bound, bound_len);
10924 } else {
10925 156806 *upper_bound_slice = rocksdb::Slice((const char *)upper_bound, bound_len);
10926 156806 *lower_bound_slice = rocksdb::Slice((const char *)lower_bound, bound_len);
10927 }
10928 218892 }
10929
10930 /**
10931 @return
10932 HA_EXIT_SUCCESS OK
10933 other HA_ERR error code (can be SE-specific)
10934 */
10935 115731 int ha_rocksdb::rnd_init(bool scan MY_ATTRIBUTE((__unused__))) {
10936
1/2
✓ Branch 0 taken 115731 times.
✗ Branch 1 not taken.
115731 DBUG_ENTER_FUNC();
10937
10938 115731 m_need_build_decoder = true;
10939 115731 m_rnd_scan_started = false;
10940
6/10
✓ Branch 0 taken 115731 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 115731 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13465 times.
✓ Branch 5 taken 102266 times.
✓ Branch 6 taken 102266 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 115731 times.
✗ Branch 9 not taken.
231462 DBUG_RETURN(
10941 index_init(has_hidden_pk(table) ? MAX_KEY : pk_index(table, m_tbl_def),
10942 false /* sorted */));
10943 }
10944
10945 /**
10946 @return
10947 HA_EXIT_SUCCESS OK
10948 other HA_ERR error code (can be SE-specific)
10949 */
10950 97051958 int ha_rocksdb::rnd_next(uchar *const buf) {
10951
1/2
✓ Branch 0 taken 97051958 times.
✗ Branch 1 not taken.
97051958 DBUG_ENTER_FUNC();
10952
10953
1/2
✓ Branch 0 taken 97051958 times.
✗ Branch 1 not taken.
97051958 check_build_decoder();
10954
10955 int rc;
10956
1/2
✓ Branch 0 taken 97051958 times.
✗ Branch 1 not taken.
97051958 ha_statistic_increment(&System_status_var::ha_read_rnd_next_count);
10957
10958 /*
10959 Since order does not matter, the scan will occur go with natural index
10960 order.
10961 */
10962
1/2
✓ Branch 0 taken 97051958 times.
✗ Branch 1 not taken.
97051958 bool is_reverse_cf = m_key_descr_arr[active_index_pos()]->m_is_reverse_cf;
10963
2/2
✓ Branch 0 taken 23218 times.
✓ Branch 1 taken 97028740 times.
97051958 if (!m_rnd_scan_started) {
10964
1/2
✓ Branch 0 taken 23218 times.
✗ Branch 1 not taken.
23218 rc = index_read_intern(buf, !is_reverse_cf /* first */);
10965 23218 m_rnd_scan_started = true;
10966 } else {
10967
2/2
✓ Branch 0 taken 24030636 times.
✓ Branch 1 taken 72998104 times.
97028740 if (is_reverse_cf) {
10968
1/2
✓ Branch 0 taken 24030636 times.
✗ Branch 1 not taken.
24030636 rc = index_next_with_direction_intern(buf, false, false);
10969 } else {
10970
1/2
✓ Branch 0 taken 72998104 times.
✗ Branch 1 not taken.
72998104 rc = index_next_with_direction_intern(buf, true, false);
10971 }
10972 }
10973
10974
1/2
✓ Branch 0 taken 97051958 times.
✗ Branch 1 not taken.
97051958 DBUG_RETURN(rc);
10975 }
10976
10977 115118 int ha_rocksdb::rnd_end() {
10978
1/2
✓ Branch 0 taken 115118 times.
✗ Branch 1 not taken.
115118 DBUG_ENTER_FUNC();
10979
2/4
✓ Branch 0 taken 115118 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 115118 times.
✗ Branch 3 not taken.
230236 DBUG_RETURN(index_end());
10980 }
10981
10982 503807 void ha_rocksdb::build_decoder() {
10983 503807 m_converter->setup_field_decoders(table->read_set, active_index,
10984 503807 m_keyread_only,
10985 503807 m_lock_rows == RDB_LOCK_WRITE);
10986 503807 }
10987
10988 186653103 void ha_rocksdb::check_build_decoder() {
10989
2/2
✓ Branch 0 taken 503807 times.
✓ Branch 1 taken 186149296 times.
186653103 if (m_need_build_decoder) {
10990 503807 build_decoder();
10991 503807 m_need_build_decoder = false;
10992 }
10993 186653103 }
10994
10995 /**
10996 @return
10997 HA_EXIT_SUCCESS OK
10998 other HA_ERR error code (can be SE-specific)
10999 */
11000 504058 int ha_rocksdb::index_init(uint idx, bool sorted) {
11001
1/2
✓ Branch 0 taken 504058 times.
✗ Branch 1 not taken.
504058 DBUG_ENTER_FUNC();
11002
11003 504058 m_need_build_decoder = true;
11004 504058 active_index = idx;
11005
11006
1/2
✓ Branch 0 taken 504058 times.
✗ Branch 1 not taken.
504058 THD *thd = ha_thd();
11007
3/6
✓ Branch 0 taken 504058 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 504058 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 504058 times.
504058 if (thd && thd->killed) {
11008 DBUG_RETURN(HA_ERR_QUERY_INTERRUPTED);
11009 }
11010
11011
1/2
✓ Branch 0 taken 504058 times.
✗ Branch 1 not taken.
504058 Rdb_transaction *const tx = get_or_create_tx(thd);
11012
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 504058 times.
504058 assert(tx != nullptr);
11013
11014 504058 active_index = idx;
11015
6/6
✓ Branch 0 taken 71471 times.
✓ Branch 1 taken 432587 times.
✓ Branch 2 taken 756 times.
✓ Branch 3 taken 70715 times.
✓ Branch 4 taken 756 times.
✓ Branch 5 taken 503302 times.
575529 if (idx != table->s->primary_key &&
11016 71471 m_key_descr_arr[idx]->is_partial_index()) {
11017 756 m_iterator.reset(
11018
1/2
✓ Branch 0 taken 756 times.
✗ Branch 1 not taken.
756 new Rdb_iterator_partial(thd, m_key_descr_arr[active_index_pos()],
11019
2/4
✓ Branch 0 taken 756 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 756 times.
✗ Branch 3 not taken.
756 m_pk_descr, m_tbl_def, table));
11020 } else {
11021 503302 m_iterator.reset(new Rdb_iterator_base(
11022
3/6
✓ Branch 0 taken 503302 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 503302 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 503302 times.
✗ Branch 5 not taken.
503302 thd, m_key_descr_arr[active_index_pos()], m_pk_descr, m_tbl_def));
11023 }
11024
11025 // If m_lock_rows is not RDB_LOCK_NONE then we will be doing a get_for_update
11026 // when accessing the index, so don't acquire the snapshot right away.
11027 // Otherwise acquire the snapshot immediately.
11028
1/2
✓ Branch 0 taken 504058 times.
✗ Branch 1 not taken.
504058 tx->acquire_snapshot(m_lock_rows == RDB_LOCK_NONE);
11029
11030
1/2
✓ Branch 0 taken 504058 times.
✗ Branch 1 not taken.
504058 DBUG_RETURN(HA_EXIT_SUCCESS);
11031 }
11032
11033 /**
11034 @return
11035 HA_EXIT_SUCCESS OK
11036 */
11037 503445 int ha_rocksdb::index_end() {
11038
1/2
✓ Branch 0 taken 503445 times.
✗ Branch 1 not taken.
503445 DBUG_ENTER_FUNC();
11039
11040 503445 m_need_build_decoder = false;
11041
11042 503445 m_iterator = nullptr;
11043
11044 503445 active_index = MAX_KEY;
11045 503445 in_range_check_pushed_down = false;
11046
11047
1/2
✓ Branch 0 taken 503445 times.
✗ Branch 1 not taken.
503445 DBUG_RETURN(HA_EXIT_SUCCESS);
11048 }
11049
11050 /**
11051 Called by the partition manager for truncating tables.
11052
11053 @return
11054 HA_EXIT_SUCCESS OK
11055 other HA_ERR error code (can be SE-specific)
11056 */
11057 276 int ha_rocksdb::truncate(dd::Table *table_def) {
11058
1/2
✓ Branch 0 taken 276 times.
✗ Branch 1 not taken.
276 DBUG_ENTER_FUNC();
11059
11060
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 276 times.
276 assert(m_tbl_def != nullptr);
11061
11062 // Reset auto_increment_value to 1 if auto-increment feature is enabled
11063 // By default, the starting valid value for auto_increment_value is 1
11064
5/8
✓ Branch 0 taken 276 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 222 times.
✓ Branch 4 taken 276 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 276 times.
✗ Branch 7 not taken.
276 DBUG_RETURN(truncate_table(
11065 m_tbl_def, "" /* actual_user_table_name */, table,
11066 table->found_next_number_field ? 1 : 0 /* auto_increment_value */,
11067 table_def));
11068 }
11069
11070 3995526 int ha_rocksdb::reset() {
11071
1/2
✓ Branch 0 taken 3995760 times.
✗ Branch 1 not taken.
3995526 DBUG_ENTER_FUNC();
11072
11073 /* Free blob data */
11074
1/2
✓ Branch 0 taken 3995597 times.
✗ Branch 1 not taken.
3995760 m_retrieved_record.Reset();
11075
1/2
✓ Branch 0 taken 3995673 times.
✗ Branch 1 not taken.
3995597 m_dup_key_retrieved_record.Reset();
11076
1/2
✓ Branch 0 taken 3995427 times.
✗ Branch 1 not taken.
3995673 release_blob_buffer();
11077 3995427 m_iterator.reset(nullptr);
11078 3995797 m_pk_iterator.reset(nullptr);
11079
1/2
✓ Branch 0 taken 3995723 times.
✗ Branch 1 not taken.
3995816 DBUG_RETURN(HA_EXIT_SUCCESS);
11080 }
11081
11082 /*
11083 Delete the row we've last read. The row is also passed as parameter.
11084
11085 @detail
11086 The caller guarantees table buf points to the row that was just read.
11087 The row is either table->record[0] or table->record[1].
11088 (Check out InnoDB: row_update_for_mysql() has "UT_NOT_USED(mysql_rec)"
11089
11090 @return
11091 HA_EXIT_SUCCESS OK
11092 other HA_ERR error code (can be SE-specific)
11093 */
11094 240972 int ha_rocksdb::delete_row(const uchar *const buf) {
11095
1/2
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
240972 DBUG_ENTER_FUNC();
11096
11097
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240972 times.
240972 assert(buf != nullptr);
11098
11099
1/2
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
240972 ha_statistic_increment(&System_status_var::ha_delete_count);
11100
1/2
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
240972 set_last_rowkey(buf);
11101
11102 240972 rocksdb::Slice key_slice(m_last_rowkey.ptr(), m_last_rowkey.length());
11103
1/2
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
240972 Rdb_transaction *const tx = get_or_create_tx(table->in_use);
11104
11105
1/2
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
240972 const uint index = pk_index(table, m_tbl_def);
11106 rocksdb::Status s =
11107
1/2
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
240972 delete_or_singledelete(index, tx, m_pk_descr->get_cf(), key_slice);
11108
2/4
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 240972 times.
240972 if (!s.ok()) {
11109 DBUG_RETURN(tx->set_status_error(table->in_use, s, *m_pk_descr, m_tbl_def));
11110 }
11111
11112 240972 longlong hidden_pk_id = 0;
11113
7/8
✓ Branch 0 taken 215319 times.
✓ Branch 1 taken 25653 times.
✓ Branch 2 taken 215319 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3291 times.
✓ Branch 5 taken 212028 times.
✓ Branch 6 taken 3291 times.
✓ Branch 7 taken 237681 times.
240972 if (m_tbl_def->m_key_count > 1 && has_hidden_pk(table)) {
11114
1/2
✓ Branch 0 taken 3291 times.
✗ Branch 1 not taken.
3291 int err = read_hidden_pk_id_from_rowkey(&hidden_pk_id);
11115
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3291 times.
3291 if (err) {
11116 DBUG_RETURN(err);
11117 }
11118 }
11119
11120 // Delete the record for every secondary index
11121
2/2
✓ Branch 0 taken 456750 times.
✓ Branch 1 taken 240972 times.
697722 for (uint i = 0; i < m_tbl_def->m_key_count; i++) {
11122
3/4
✓ Branch 0 taken 456750 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 215778 times.
✓ Branch 3 taken 240972 times.
456750 if (!is_pk(i, table, m_tbl_def)) {
11123 int packed_size;
11124 215778 const Rdb_key_def &kd = *m_key_descr_arr[i];
11125
11126 // The unique key should be locked so that behavior is
11127 // similar to InnoDB and reduce conflicts. The key
11128 // used for locking does not include the extended fields.
11129 215778 const KEY *key_info = &table->key_info[i];
11130
2/2
✓ Branch 0 taken 1101 times.
✓ Branch 1 taken 214677 times.
215778 if (key_info->flags & HA_NOSAME) {
11131 1101 uint user_defined_key_parts = key_info->user_defined_key_parts;
11132 1101 uint n_null_fields = 0;
11133
11134
1/2
✓ Branch 0 taken 1101 times.
✗ Branch 1 not taken.
1101 packed_size = kd.pack_record(table, m_pack_buffer, buf,
11135 m_sk_packed_tuple, nullptr, false, 0,
11136 user_defined_key_parts, &n_null_fields);
11137
11138 // NULL fields are considered unique, so no lock is needed
11139
1/2
✓ Branch 0 taken 1101 times.
✗ Branch 1 not taken.
1101 if (n_null_fields == 0) {
11140 rocksdb::Slice sk_slice(
11141 1101 reinterpret_cast<const char *>(m_sk_packed_tuple), packed_size);
11142
1/2
✓ Branch 0 taken 1101 times.
✗ Branch 1 not taken.
1101 const rocksdb::Status s = get_for_update(tx, kd, sk_slice);
11143
2/4
✓ Branch 0 taken 1101 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1101 times.
1101 if (!s.ok()) {
11144 DBUG_RETURN(tx->set_status_error(table->in_use, s, kd, m_tbl_def));
11145 }
11146
1/2
✓ Branch 0 taken 1101 times.
✗ Branch 1 not taken.
1101 }
11147 }
11148
11149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 215778 times.
215778 if (kd.is_partial_index()) {
11150 // Obtain shared lock on prefix.
11151 int rc = acquire_prefix_lock(kd, tx, buf);
11152 if (rc) DBUG_RETURN(rc);
11153 }
11154
11155
1/2
✓ Branch 0 taken 215778 times.
✗ Branch 1 not taken.
215778 packed_size = kd.pack_record(table, m_pack_buffer, buf, m_sk_packed_tuple,
11156 nullptr, false, hidden_pk_id);
11157 rocksdb::Slice secondary_key_slice(
11158 215778 reinterpret_cast<const char *>(m_sk_packed_tuple), packed_size);
11159
2/4
✓ Branch 0 taken 215778 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 215778 times.
✗ Branch 3 not taken.
215778 tx->get_indexed_write_batch()->SingleDelete(kd.get_cf(),
11160 secondary_key_slice);
11161 }
11162 }
11163
11164
1/2
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
240972 tx->log_table_write_op(m_tbl_def);
11165
11166
2/4
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 240972 times.
240972 if (do_bulk_commit(tx)) {
11167 DBUG_RETURN(HA_ERR_ROCKSDB_BULK_LOAD);
11168 }
11169
11170 // Not protected by ddl_manger lock for performance
11171 // reasons. This is an estimate value anyway.
11172
1/2
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
240972 dec_table_n_rows();
11173
1/2
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
240972 update_table_stats_if_needed();
11174
1/2
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
240972 update_row_stats(ROWS_DELETED);
11175
11176
1/2
✓ Branch 0 taken 240972 times.
✗ Branch 1 not taken.
240972 DBUG_RETURN(HA_EXIT_SUCCESS);
11177 240972 }
11178
11179 384400 rocksdb::Status ha_rocksdb::delete_or_singledelete(
11180 uint index, Rdb_transaction *const tx,
11181 rocksdb::ColumnFamilyHandle *const column_family,
11182 const rocksdb::Slice &key) {
11183 384400 const bool assume_tracked = can_assume_tracked(ha_thd());
11184
2/2
✓ Branch 0 taken 104375 times.
✓ Branch 1 taken 280025 times.
384400 if (can_use_single_delete(index)) {
11185 104375 return tx->single_delete(column_family, key, assume_tracked);
11186 }
11187 280025 return tx->delete_key(column_family, key, assume_tracked);
11188 }
11189
11190 249 int ha_rocksdb::adjust_handler_stats_table_scan(ha_statistics *ha_stats,
11191 Rdb_tbl_def *tbl_def) {
11192
1/2
✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
249 DBUG_ENTER_FUNC();
11193
11194 249 bool should_recalc_stats = false;
11195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 if (static_cast<longlong>(ha_stats->data_file_length) < 0) {
11196 ha_stats->data_file_length = 0;
11197 should_recalc_stats = true;
11198 }
11199
11200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 if (static_cast<longlong>(ha_stats->index_file_length) < 0) {
11201 ha_stats->index_file_length = 0;
11202 should_recalc_stats = true;
11203 }
11204
11205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 if (static_cast<longlong>(ha_stats->records) < 0) {
11206 ha_stats->records = 1;
11207 should_recalc_stats = true;
11208 }
11209
11210
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 if (should_recalc_stats) {
11211 // If any of the stats is corrupt, add the table to the index stats
11212 // recalc queue.
11213 rdb_is_thread.add_index_stats_request(tbl_def->full_tablename());
11214 }
11215
1/2
✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
249 DBUG_RETURN(HA_EXIT_SUCCESS);
11216 }
11217
11218 463264 int ha_rocksdb::update_stats(ha_statistics *ha_stats, Rdb_tbl_def *tbl_def,
11219 bool from_handler) {
11220 /*
11221 Test only to simulate corrupted stats
11222 */
11223
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 463262 times.
463264 DBUG_EXECUTE_IF("myrocks_simulate_negative_stats", {
11224 auto pk_def = tbl_def->get_pk_def();
11225 pk_def->m_stats.m_actual_disk_size = -pk_def->m_stats.m_actual_disk_size;
11226 });
11227
11228 463265 rocksdb_get_stats(ha_stats, tbl_def);
11229
2/2
✓ Branch 0 taken 249 times.
✓ Branch 1 taken 463015 times.
463264 if (rocksdb_table_stats_use_table_scan) {
11230 249 int ret = adjust_handler_stats_table_scan(ha_stats, tbl_def);
11231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 if (ret != HA_EXIT_SUCCESS) {
11232 return ret;
11233 }
11234 } else {
11235 463015 int ret = adjust_handler_stats_sst_and_memtable(ha_stats, tbl_def);
11236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 463014 times.
463014 if (ret != HA_EXIT_SUCCESS) {
11237 return ret;
11238 }
11239 }
11240
11241
2/2
✓ Branch 0 taken 44513 times.
✓ Branch 1 taken 418750 times.
463263 if (rocksdb_debug_optimizer_n_rows > 0) {
11242 44513 ha_stats->records = rocksdb_debug_optimizer_n_rows;
11243 }
11244
11245
2/2
✓ Branch 0 taken 408581 times.
✓ Branch 1 taken 54682 times.
463263 if (ha_stats->records != 0) {
11246 408581 ha_stats->mean_rec_length = ha_stats->data_file_length / ha_stats->records;
11247 }
11248
11249 // Skip the rest if we are called from ha_rocksdb::info which will perform
11250 // following updates based on flag. Alawys update auto_inc_val is expensive
11251 // from ha_rocksdb::info as it involves a DBImpl::Get so we don't want to
11252 // do that in steady state. When called from rocksdb_get_table_statistics
11253 // it is fine as it is much less frequent
11254
2/2
✓ Branch 0 taken 396 times.
✓ Branch 1 taken 462867 times.
463263 if (!from_handler) {
11255 // HA_STATUS_TIME
11256 396 ha_stats->update_time = tbl_def->m_update_time;
11257
11258 // HA_STATUS_AUTO
11259 // Because we haven't opened the table yet, we need to load auto incr
11260 // value here. Note we won't know if the table actually has auto incr
11261 // without opening the table, so there is a corner case it'll end up
11262 // being NULL if the table has just been created and haven't been
11263 // opened yet - InnoDB has the same issue
11264
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 139 times.
396 if (tbl_def->m_auto_incr_val == 0) {
11265 // Unfortunately in this case we don't know if we actually have auto
11266 // increment without opening the table, so we'd have to load the value
11267 // always even if the table doesn't have auto increment
11268
1/2
✓ Branch 0 taken 257 times.
✗ Branch 1 not taken.
257 const GL_INDEX_ID &gl_index_id = tbl_def->get_autoincr_gl_index_id();
11269 514 if (!dict_manager.get_dict_manager_selector_const(gl_index_id.cf_id)
11270
4/6
✓ Branch 0 taken 257 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 257 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 203 times.
✓ Branch 5 taken 54 times.
257 ->get_auto_incr_val(gl_index_id,
11271 &ha_stats->auto_increment_value)) {
11272 203 ha_stats->auto_increment_value = 0;
11273 }
11274 } else {
11275 139 ha_stats->auto_increment_value = tbl_def->m_auto_incr_val;
11276 }
11277 }
11278
11279 463263 return HA_EXIT_SUCCESS;
11280 }
11281
11282 /**
11283 @return
11284 HA_EXIT_SUCCESS OK
11285 HA_EXIT_FAILURE Error
11286 */
11287 469687 int ha_rocksdb::info(uint flag) {
11288
1/2
✓ Branch 0 taken 469693 times.
✗ Branch 1 not taken.
469687 DBUG_ENTER_FUNC();
11289
11290
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 469693 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
469693 if (!table) DBUG_RETURN(HA_EXIT_FAILURE);
11291
11292
2/2
✓ Branch 0 taken 462868 times.
✓ Branch 1 taken 6825 times.
469693 if (flag & HA_STATUS_VARIABLE) {
11293
1/2
✓ Branch 0 taken 462866 times.
✗ Branch 1 not taken.
462868 int ret = update_stats(&stats, m_tbl_def, /* from_handler */ true);
11294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 462866 times.
462866 if (ret != HA_EXIT_SUCCESS) {
11295 return ret;
11296 }
11297 }
11298
11299
2/2
✓ Branch 0 taken 464491 times.
✓ Branch 1 taken 5200 times.
469691 if (flag & (HA_STATUS_VARIABLE | HA_STATUS_CONST)) {
11300 464491 ref_length = m_pk_descr->max_storage_fmt_length();
11301
11302
2/2
✓ Branch 0 taken 760882 times.
✓ Branch 1 taken 464487 times.
1225369 for (uint i = 0; i < m_tbl_def->m_key_count; i++) {
11303
3/4
✓ Branch 0 taken 760881 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39527 times.
✓ Branch 3 taken 721354 times.
760882 if (is_hidden_pk(i, table, m_tbl_def)) {
11304 39527 continue;
11305 }
11306 721354 KEY *const k = &table->key_info[i];
11307 721354 auto records = stats.records;
11308
2/2
✓ Branch 0 taken 1613730 times.
✓ Branch 1 taken 721353 times.
2335083 for (uint j = 0; j < k->actual_key_parts; j++) {
11309 1613730 const Rdb_index_stats &k_stats = m_key_descr_arr[i]->m_stats;
11310 1613728 rec_per_key_t x = REC_PER_KEY_UNKNOWN;
11311
11312 // Doesn't make sense to calculate cardinality if there are no records
11313
2/2
✓ Branch 0 taken 1457619 times.
✓ Branch 1 taken 156109 times.
1613728 if (records > 0) {
11314
3/4
✓ Branch 0 taken 1457619 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 864225 times.
✓ Branch 3 taken 593394 times.
2915238 if (k_stats.m_distinct_keys_per_prefix.size() > j &&
11315
2/2
✓ Branch 0 taken 864225 times.
✓ Branch 1 taken 593394 times.
1457619 k_stats.m_distinct_keys_per_prefix[j] > 0) {
11316 1728450 x = (rec_per_key_t)k_stats.m_rows /
11317 864225 k_stats.m_distinct_keys_per_prefix[j];
11318
11319 /*
11320 If the number of rows is less than the number of prefixes (due to
11321 sampling), the average number of rows with the same prefix is 1.
11322 */
11323
2/2
✓ Branch 0 taken 814 times.
✓ Branch 1 taken 863411 times.
864225 if (x < 1) {
11324 814 x = 1;
11325 }
11326 }
11327
11328
4/4
✓ Branch 0 taken 593394 times.
✓ Branch 1 taken 864225 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 593376 times.
1457619 if ((x == REC_PER_KEY_UNKNOWN &&
11329 864243 rocksdb_debug_optimizer_no_zero_cardinality) ||
11330
2/2
✓ Branch 0 taken 132267 times.
✓ Branch 1 taken 731976 times.
864243 rocksdb_debug_optimizer_n_rows > 0) {
11331 // Fake cardinality implementation. For example, (idx1, idx2, idx3)
11332 // index
11333 // will have rec_per_key for (idx1)=4, (idx1,2)=2, and (idx1,2,3)=1.
11334 // rec_per_key for the whole index is 1, and multiplied by 2^n if
11335 // n suffix columns of the index are not used.
11336
2/2
✓ Branch 0 taken 714987 times.
✓ Branch 1 taken 10656 times.
725643 if (rocksdb_debug_cardinality_multiplier == 2) {
11337 714987 x = 1 << (k->actual_key_parts - j - 1);
11338 } else {
11339 10656 x = 1;
11340
2/2
✓ Branch 0 taken 15984 times.
✓ Branch 1 taken 10656 times.
26640 for (uint kp = 1; kp <= k->actual_key_parts - j - 1; kp++) {
11341 15984 x *= rocksdb_debug_cardinality_multiplier;
11342 }
11343 }
11344 }
11345
11346
2/2
✓ Branch 0 taken 11288 times.
✓ Branch 1 taken 1446331 times.
1457619 if (x > records) x = records;
11347 }
11348
11349 // 1 <= x <= records, or x = REC_PER_KEY_UNKNOWN
11350 1613728 k->set_records_per_key(j, x);
11351 }
11352 }
11353
11354
1/2
✓ Branch 0 taken 464488 times.
✗ Branch 1 not taken.
464487 stats.create_time = m_tbl_def->get_create_time();
11355 }
11356
11357
2/2
✓ Branch 0 taken 2752 times.
✓ Branch 1 taken 466936 times.
469688 if (flag & HA_STATUS_TIME) {
11358 2752 stats.update_time = m_tbl_def->m_update_time;
11359 }
11360
11361
2/2
✓ Branch 0 taken 3071 times.
✓ Branch 1 taken 466617 times.
469688 if (flag & HA_STATUS_ERRKEY) {
11362 /*
11363 Currently we support only primary keys so we know which key had a
11364 uniqueness violation.
11365 */
11366 3071 errkey = m_dupp_errkey;
11367 }
11368
11369
2/2
✓ Branch 0 taken 2922 times.
✓ Branch 1 taken 466766 times.
469688 if (flag & HA_STATUS_AUTO) {
11370 2922 stats.auto_increment_value = m_tbl_def->m_auto_incr_val;
11371 }
11372
11373
1/2
✓ Branch 0 taken 469691 times.
✗ Branch 1 not taken.
469688 DBUG_RETURN(HA_EXIT_SUCCESS);
11374 }
11375
11376 192429 void ha_rocksdb::position(const uchar *const record) {
11377
1/2
✓ Branch 0 taken 192429 times.
✗ Branch 1 not taken.
192429 DBUG_ENTER_FUNC();
11378
11379 192429 longlong hidden_pk_id = 0;
11380
6/10
✓ Branch 0 taken 192429 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 71905 times.
✓ Branch 3 taken 120524 times.
✓ Branch 4 taken 71905 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 71905 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 192429 times.
192429 if (has_hidden_pk(table) && read_hidden_pk_id_from_rowkey(&hidden_pk_id)) {
11381 assert(false); // should never reach here
11382 }
11383
11384 /*
11385 Get packed primary key value from the record.
11386
11387 (Note: m_last_rowkey has the packed PK of last-read-row, which allows to
11388 handle most cases, but there is an exception to this: when slave applies
11389 RBR events, it fills the record and then calls position(); rnd_pos())
11390
11391 Also note that we *can* rely on PK column values being available. This is
11392 because table_flags() includes HA_PRIMARY_KEY_REQUIRED_FOR_POSITION bit.
11393 When that is true, table->prepare_for_position() adds PK columns into the
11394 read set (this may potentially disable index-only access when PK column
11395 cannot be restored from its mem-comparable form in the secondary indexes).
11396 */
11397 192429 const uint packed_size = m_pk_descr->pack_record(
11398
1/2
✓ Branch 0 taken 192429 times.
✗ Branch 1 not taken.
192429 table, m_pack_buffer, record, ref, nullptr, false, hidden_pk_id);
11399
11400 /*
11401 It could be that mem-comparable form of PK occupies less than ref_length
11402 bytes. Fill the remainder with zeros.
11403 */
11404
2/2
✓ Branch 0 taken 1255 times.
✓ Branch 1 taken 191174 times.
192429 if (ref_length > packed_size) {
11405 1255 memset(ref + packed_size, 0, ref_length - packed_size);
11406 }
11407
11408
1/2
✓ Branch 0 taken 192429 times.
✗ Branch 1 not taken.
384858 DBUG_VOID_RETURN;
11409 }
11410
11411 /**
11412 @return
11413 HA_EXIT_SUCCESS OK
11414 other HA_ERR error code (can be SE-specific)
11415 */
11416 122275 int ha_rocksdb::rnd_pos(uchar *const buf, uchar *const pos) {
11417
1/2
✓ Branch 0 taken 122275 times.
✗ Branch 1 not taken.
122275 DBUG_ENTER_FUNC();
11418
11419
1/2
✓ Branch 0 taken 122275 times.
✗ Branch 1 not taken.
122275 check_build_decoder();
11420
11421 int rc;
11422 size_t len;
11423
11424
1/2
✓ Branch 0 taken 122275 times.
✗ Branch 1 not taken.
122275 ha_statistic_increment(&System_status_var::ha_read_rnd_count);
11425
1/2
✓ Branch 0 taken 122275 times.
✗ Branch 1 not taken.
244550 len = m_pk_descr->key_length(table,
11426 122275 rocksdb::Slice((const char *)pos, ref_length));
11427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122275 times.
122275 if (len == size_t(-1)) {
11428 DBUG_RETURN(HA_ERR_ROCKSDB_CORRUPT_DATA); /* Data corruption? */
11429 }
11430
11431
1/2
✓ Branch 0 taken 122275 times.
✗ Branch 1 not taken.
122275 rc = get_row_by_rowid(buf, pos, len);
11432
11433
2/2
✓ Branch 0 taken 122269 times.
✓ Branch 1 taken 6 times.
122275 if (!rc) {
11434
1/2
✓ Branch 0 taken 122269 times.
✗ Branch 1 not taken.
122269 update_row_stats(ROWS_READ);
11435 }
11436
11437
1/2
✓ Branch 0 taken 122275 times.
✗ Branch 1 not taken.
122275 DBUG_RETURN(rc);
11438 }
11439
11440 /*
11441 @brief
11442 Calculate (if needed) the bitmap of indexes that are modified by the
11443 current query
11444
11445 @detail
11446 The calculation done by checking index definitions against the
11447 table->write_set
11448 column bitmap.
11449 */
11450
11451 265727 void ha_rocksdb::calc_updated_indexes() {
11452 265727 m_update_scope.clear_all();
11453
11454
2/2
✓ Branch 0 taken 534969 times.
✓ Branch 1 taken 265727 times.
800696 for (uint keynr = 0; keynr < table->s->keys; keynr++) {
11455 534969 const Rdb_key_def &kd = *m_key_descr_arr[keynr];
11456 /* Walk over all key parts, including the "extended key" suffix */
11457 534969 const uint key_parts = kd.get_key_parts();
11458
2/2
✓ Branch 0 taken 535569 times.
✓ Branch 1 taken 544 times.
536113 for (uint kp = 0; kp < key_parts; kp++) {
11459
6/6
✓ Branch 0 taken 85917 times.
✓ Branch 1 taken 449652 times.
✓ Branch 2 taken 600 times.
✓ Branch 3 taken 85317 times.
✓ Branch 4 taken 600 times.
✓ Branch 5 taken 534969 times.
535569 if (has_hidden_pk(table) && kp + 1 == key_parts) break;
11460
11461 534969 Field *const field = kd.get_table_field_for_part_no(table, kp);
11462
2/2
✓ Branch 0 taken 533825 times.
✓ Branch 1 taken 1144 times.
534969 if (bitmap_is_set(table->write_set, field->field_index())) {
11463 533825 m_update_scope.set_bit(keynr);
11464 533825 break;
11465 }
11466 }
11467 }
11468 265727 }
11469
11470 /**
11471 Update an existing row
11472 @param[in] old_data nullptr for write, non-null for update
11473 @param[in] new_data non-null for write/update
11474 @return
11475 HA_EXIT_SUCCESS OK
11476 other HA_ERR error code (can be SE-specific)
11477 */
11478 265728 int ha_rocksdb::update_row(const uchar *const old_data, uchar *const new_data) {
11479
1/2
✓ Branch 0 taken 265728 times.
✗ Branch 1 not taken.
265728 DBUG_ENTER_FUNC();
11480
11481
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 265728 times.
265728 assert(old_data != nullptr);
11482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 265728 times.
265728 assert(new_data != nullptr);
11483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 265728 times.
265728 assert(m_lock_rows == RDB_LOCK_WRITE);
11484 /*
11485 old_data points to record we're updating. It is the same as the record
11486 we've just read (for multi-table UPDATE, too, because SQL layer will make
11487 an rnd_pos() call to re-read the record before calling update_row())
11488 */
11489
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 265728 times.
265728 assert(new_data == table->record[0]);
11490
11491
1/2
✓ Branch 0 taken 265728 times.
✗ Branch 1 not taken.
265728 ha_statistic_increment(&System_status_var::ha_update_count);
11492
2/4
✓ Branch 0 taken 265728 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 265728 times.
✗ Branch 3 not taken.
265728 const int rv = update_write_row(old_data, new_data, skip_unique_check());
11493
11494
2/2
✓ Branch 0 taken 265662 times.
✓ Branch 1 taken 66 times.
265728 if (rv == 0) {
11495
1/2
✓ Branch 0 taken 265662 times.
✗ Branch 1 not taken.
265662 update_table_stats_if_needed();
11496
1/2
✓ Branch 0 taken 265662 times.
✗ Branch 1 not taken.
265662 update_row_stats(ROWS_UPDATED);
11497 }
11498
11499
1/2
✓ Branch 0 taken 265728 times.
✗ Branch 1 not taken.
265728 DBUG_RETURN(rv);
11500 }
11501
11502 70931408 void ha_rocksdb::update_table_stats_if_needed() {
11503
1/2
✓ Branch 0 taken 70991479 times.
✗ Branch 1 not taken.
70931408 DBUG_ENTER_FUNC();
11504
11505
2/2
✓ Branch 0 taken 70962379 times.
✓ Branch 1 taken 29100 times.
70991479 if (!rocksdb_table_stats_use_table_scan) {
11506
1/2
✓ Branch 0 taken 70968791 times.
✗ Branch 1 not taken.
70962379 DBUG_VOID_RETURN;
11507 }
11508
11509 /*
11510 InnoDB performs a similar operation to update counters during query
11511 processing. Because the changes in MyRocks are made to a write batch,
11512 it is possible for the table scan cardinality calculation to trigger
11513 before the transaction performing the update commits. Hence the
11514 cardinality scan might miss the keys for these pending transactions.
11515 */
11516 29100 uint64 counter = m_tbl_def->m_tbl_stats.m_stat_modified_counter++;
11517 29100 uint64 n_rows = m_tbl_def->m_tbl_stats.m_stat_n_rows;
11518
11519 59472 if (counter > std::max(rocksdb_table_stats_recalc_threshold_count,
11520
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 30292 times.
30372 static_cast<long long unsigned int>(
11521 29100 n_rows * rocksdb_table_stats_recalc_threshold_pct /
11522 100.0))) {
11523 // Add the table to the recalc queue
11524
1/2
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
80 rdb_is_thread.add_index_stats_request(m_tbl_def->full_tablename());
11525 80 m_tbl_def->m_tbl_stats.m_stat_modified_counter = 0;
11526 }
11527
11528
1/2
✓ Branch 0 taken 30372 times.
✗ Branch 1 not taken.
30372 DBUG_VOID_RETURN;
11529 }
11530
11531 /* The following function was copied from ha_blackhole::store_lock: */
11532 3986011 THR_LOCK_DATA **ha_rocksdb::store_lock(THD *const thd, THR_LOCK_DATA **to,
11533 enum thr_lock_type lock_type) {
11534
1/2
✓ Branch 0 taken 3986209 times.
✗ Branch 1 not taken.
3986011 DBUG_ENTER_FUNC();
11535
11536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3986209 times.
3986209 assert(thd != nullptr);
11537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3986209 times.
3986209 assert(to != nullptr);
11538
11539
1/2
✓ Branch 0 taken 3986092 times.
✗ Branch 1 not taken.
3986209 bool in_lock_tables = my_core::thd_in_lock_tables(thd);
11540
11541 /* First, make a decision about MyRocks's internal locking */
11542
2/2
✓ Branch 0 taken 3831982 times.
✓ Branch 1 taken 154110 times.
3986092 if (lock_type >= TL_WRITE_ALLOW_WRITE) {
11543 3831982 m_lock_rows = RDB_LOCK_WRITE;
11544
2/2
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 153909 times.
154110 } else if (lock_type == TL_READ_WITH_SHARED_LOCKS) {
11545 201 m_lock_rows = RDB_LOCK_READ;
11546
2/2
✓ Branch 0 taken 150018 times.
✓ Branch 1 taken 3891 times.
153909 } else if (lock_type != TL_IGNORE) {
11547 150018 m_lock_rows = RDB_LOCK_NONE;
11548
3/4
✓ Branch 0 taken 150018 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 150006 times.
150018 if (THDVAR(thd, lock_scanned_rows)) {
11549 /*
11550 The following logic was copied directly from
11551 ha_innobase::store_lock_with_x_type() in
11552 storage/innobase/handler/ha_innodb.cc and causes MyRocks to leave
11553 locks in place on rows that are in a table that is not being updated.
11554 */
11555
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 const uint sql_command = my_core::thd_sql_command(thd);
11556
3/6
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
12 if ((lock_type == TL_READ && in_lock_tables) ||
11557
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 (lock_type == TL_READ_HIGH_PRIORITY && in_lock_tables) ||
11558
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 lock_type == TL_READ_WITH_SHARED_LOCKS ||
11559
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 lock_type == TL_READ_NO_INSERT ||
11560
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 (lock_type != TL_IGNORE && sql_command != SQLCOM_SELECT)) {
11561
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 ulong tx_isolation = my_core::thd_tx_isolation(thd);
11562
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
12 if (sql_command != SQLCOM_CHECKSUM &&
11563
4/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
6 ((my_core::thd_test_options(thd, OPTION_BIN_LOG) &&
11564
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 tx_isolation > ISO_READ_COMMITTED) ||
11565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 tx_isolation == ISO_SERIALIZABLE ||
11566
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 (lock_type != TL_READ && lock_type != TL_READ_NO_INSERT) ||
11567
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 (sql_command != SQLCOM_INSERT_SELECT &&
11568
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 sql_command != SQLCOM_REPLACE_SELECT &&
11569
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 sql_command != SQLCOM_UPDATE && sql_command != SQLCOM_DELETE &&
11570 sql_command != SQLCOM_CREATE_TABLE))) {
11571 6 m_lock_rows = RDB_LOCK_READ;
11572 }
11573 }
11574 }
11575 }
11576
11577 /* Then, tell the SQL layer what kind of locking it should use: */
11578
3/4
✓ Branch 0 taken 3982085 times.
✓ Branch 1 taken 4007 times.
✓ Branch 2 taken 3982173 times.
✗ Branch 3 not taken.
3986092 if (lock_type != TL_IGNORE && m_db_lock.type == TL_UNLOCK) {
11579 /*
11580 Here is where we get into the guts of a row level lock.
11581 If TL_UNLOCK is set
11582 If we are not doing a LOCK TABLE or DISCARD/IMPORT
11583 TABLESPACE, then allow multiple writers
11584 */
11585
11586
1/2
✓ Branch 0 taken 3831975 times.
✗ Branch 1 not taken.
3831967 if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && lock_type <= TL_WRITE) &&
11587
8/10
✓ Branch 0 taken 3831967 times.
✓ Branch 1 taken 150206 times.
✓ Branch 2 taken 3831680 times.
✓ Branch 3 taken 295 times.
✓ Branch 4 taken 3831584 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3831604 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3831616 times.
✓ Branch 9 taken 150461 times.
7814140 !in_lock_tables && !my_core::thd_tablespace_op(thd)) {
11588 3831616 lock_type = TL_WRITE_ALLOW_WRITE;
11589 }
11590
11591 /*
11592 In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
11593 MySQL would use the lock TL_READ_NO_INSERT on t2, and that
11594 would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
11595 to t2. Convert the lock to a normal read lock to allow
11596 concurrent inserts to t2.
11597 */
11598
11599
4/4
✓ Branch 0 taken 3972 times.
✓ Branch 1 taken 3978105 times.
✓ Branch 2 taken 3947 times.
✓ Branch 3 taken 25 times.
3982077 if (lock_type == TL_READ_NO_INSERT && !in_lock_tables) {
11600 3947 lock_type = TL_READ;
11601 }
11602
11603 3982077 m_db_lock.type = lock_type;
11604 }
11605
11606 3985996 m_locked_row_action = THR_WAIT;
11607
2/2
✓ Branch 0 taken 3982155 times.
✓ Branch 1 taken 3841 times.
3985996 if (lock_type != TL_IGNORE) {
11608 3982155 auto action = table->pos_in_table_list->lock_descriptor().action;
11609
3/3
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 3981959 times.
3982031 switch (action) {
11610 33 case THR_SKIP:
11611 33 m_locked_row_action = THR_SKIP;
11612 33 break;
11613 39 case THR_NOWAIT:
11614 39 m_locked_row_action = THR_NOWAIT;
11615 39 break;
11616 3981959 default:
11617 3981959 break;
11618 }
11619 }
11620
11621 3985872 *to++ = &m_db_lock;
11622
11623
1/2
✓ Branch 0 taken 3986230 times.
✗ Branch 1 not taken.
3985872 DBUG_RETURN(to);
11624 }
11625
11626 3983358 void ha_rocksdb::read_thd_vars(THD *const thd) {
11627 3983358 m_store_row_debug_checksums = THDVAR(thd, store_row_debug_checksums);
11628 3983834 m_converter->set_verify_row_debug_checksums(
11629 3983739 THDVAR(thd, verify_row_debug_checksums));
11630 3983594 m_checksums_pct = THDVAR(thd, checksums_pct);
11631 3983831 }
11632
11633 /**
11634 @return
11635 HA_EXIT_SUCCESS OK
11636 other HA_ERR error code (cannot be SE-specific)
11637 */
11638 7967369 int ha_rocksdb::external_lock(THD *const thd, int lock_type) {
11639
1/2
✓ Branch 0 taken 7967604 times.
✗ Branch 1 not taken.
7967369 DBUG_ENTER_FUNC();
11640
11641
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7967604 times.
7967604 assert(thd != nullptr);
11642
11643 7967604 int res = HA_EXIT_SUCCESS;
11644
1/2
✓ Branch 0 taken 7967427 times.
✗ Branch 1 not taken.
7967604 int binlog_format = my_core::thd_binlog_format(thd);
11645
2/4
✓ Branch 0 taken 7967471 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7967500 times.
✗ Branch 3 not taken.
7967427 bool unsafe_for_binlog = THDVAR(ha_thd(), unsafe_for_binlog);
11646
6/6
✓ Branch 0 taken 3808970 times.
✓ Branch 1 taken 24355 times.
✓ Branch 2 taken 3808598 times.
✓ Branch 3 taken 372 times.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 3808568 times.
3833325 if (lock_type == F_WRLCK && !thd->rli_slave && !unsafe_for_binlog &&
11647
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 24 times.
30 binlog_format != BINLOG_FORMAT_ROW &&
11648
4/4
✓ Branch 0 taken 3833325 times.
✓ Branch 1 taken 4134175 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 7967494 times.
11800825 binlog_format != BINLOG_FORMAT_UNSPEC &&
11649
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 my_core::thd_binlog_filter_ok(thd)) {
11650
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 my_error(ER_REQUIRE_ROW_BINLOG_FORMAT, MYF(0));
11651
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_RETURN(HA_ERR_UNSUPPORTED);
11652 }
11653
11654
2/2
✓ Branch 0 taken 3983825 times.
✓ Branch 1 taken 3983669 times.
7967494 if (lock_type == F_UNLCK) {
11655
1/2
✓ Branch 0 taken 3983820 times.
✗ Branch 1 not taken.
3983825 Rdb_transaction *const tx = get_tx_from_thd(thd);
11656
11657
1/2
✓ Branch 0 taken 3983821 times.
✗ Branch 1 not taken.
3983820 if (tx) {
11658
1/2
✓ Branch 0 taken 3983810 times.
✗ Branch 1 not taken.
3983821 tx->io_perf_end_and_record(&m_io_perf);
11659
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3983810 times.
3983810 assert(tx->m_n_mysql_tables_in_use > 0);
11660 3983810 tx->m_n_mysql_tables_in_use--;
11661
4/4
✓ Branch 0 taken 3975488 times.
✓ Branch 1 taken 8322 times.
✓ Branch 2 taken 3554204 times.
✓ Branch 3 taken 429556 times.
7959248 if (tx->m_n_mysql_tables_in_use == 0 &&
11662
3/4
✓ Branch 0 taken 3975438 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3554191 times.
✓ Branch 3 taken 421247 times.
3975488 !my_core::thd_test_options(thd,
11663 OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
11664 /*
11665 Do like InnoDB: when we get here, it's time to commit a
11666 single-statement transaction.
11667
11668 If the statement involved multiple tables, this code will be executed
11669 for each of them, but that's ok because non-first tx->commit() calls
11670 will be no-ops.
11671 */
11672
2/4
✓ Branch 0 taken 3554079 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3554079 times.
3554204 if (tx->commit_or_rollback()) {
11673 res = HA_ERR_INTERNAL_ERROR;
11674 }
11675 }
11676 }
11677 } else {
11678
5/6
✓ Branch 0 taken 3983454 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3983452 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 3983515 times.
7967197 if (my_core::thd_tx_isolation(thd) < ISO_READ_COMMITTED ||
11679
2/4
✓ Branch 0 taken 3983528 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3983561 times.
3983452 my_core::thd_tx_isolation(thd) > ISO_REPEATABLE_READ) {
11680 15 my_error(ER_ISOLATION_MODE_NOT_SUPPORTED, MYF(0),
11681
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 tx_isolation_names[my_core::thd_tx_isolation(thd)]);
11682
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 DBUG_RETURN(HA_ERR_UNSUPPORTED);
11683 }
11684 /*
11685 It's nice to do the following on start of every statement. The problem
11686 is, handler->start_stmt() is not called for INSERTs.
11687 So, we put this code here.
11688 */
11689
1/2
✓ Branch 0 taken 3983250 times.
✗ Branch 1 not taken.
3983515 Rdb_transaction *const tx = get_or_create_tx(thd);
11690
1/2
✓ Branch 0 taken 3983495 times.
✗ Branch 1 not taken.
3983250 read_thd_vars(thd);
11691
11692
3/4
✓ Branch 0 taken 3983547 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 414242 times.
✓ Branch 3 taken 3569305 times.
3983495 if (skip_unique_check()) {
11693
2/2
✓ Branch 0 taken 359 times.
✓ Branch 1 taken 413883 times.
414242 if ((thd->lex->sql_command == SQLCOM_INSERT ||
11694
2/2
✓ Branch 0 taken 223 times.
✓ Branch 1 taken 136 times.
359 thd->lex->sql_command == SQLCOM_LOAD ||
11695
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 222 times.
223 thd->lex->sql_command == SQLCOM_REPLACE) &&
11696
2/2
✓ Branch 0 taken 414016 times.
✓ Branch 1 taken 4 times.
414020 (thd->lex->duplicates == DUP_REPLACE ||
11697
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 414015 times.
414016 thd->lex->duplicates == DUP_UPDATE)) {
11698
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 my_error(ER_ON_DUPLICATE_DISABLED, MYF(0), thd->query().str);
11699
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 DBUG_RETURN(HA_ERR_UNSUPPORTED);
11700 }
11701 }
11702
11703
2/2
✓ Branch 0 taken 3832978 times.
✓ Branch 1 taken 150564 times.
3983542 if (lock_type == F_WRLCK) {
11704
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3832901 times.
3832978 if (tx->is_tx_read_only()) {
11705
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 my_error(ER_UPDATES_WITH_CONSISTENT_SNAPSHOT, MYF(0));
11706
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(HA_ERR_UNSUPPORTED);
11707 }
11708
11709 /*
11710 SQL layer signals us to take a write lock. It does so when starting DML
11711 statement. We should put locks on the rows we're reading.
11712
11713 Note: sometimes, external_lock() can be called without a prior
11714 ::store_lock call. That's why we need to set lock_* members here, too.
11715 */
11716 3832901 m_lock_rows = RDB_LOCK_WRITE;
11717
11718
1/2
✓ Branch 0 taken 3833035 times.
✗ Branch 1 not taken.
3832901 if (thd->lex->sql_command == SQLCOM_CREATE_INDEX ||
11719
1/2
✓ Branch 0 taken 3833074 times.
✗ Branch 1 not taken.
3833035 thd->lex->sql_command == SQLCOM_DROP_INDEX ||
11720
2/2
✓ Branch 0 taken 1866 times.
✓ Branch 1 taken 3831208 times.
3833074 thd->lex->sql_command == SQLCOM_ALTER_TABLE) {
11721 1693 tx->m_ddl_transaction = true;
11722 }
11723 }
11724 3983465 tx->m_n_mysql_tables_in_use++;
11725
1/2
✓ Branch 0 taken 3983706 times.
✗ Branch 1 not taken.
3983465 rocksdb_register_tx(rocksdb_hton, thd, tx);
11726
1/2
✓ Branch 0 taken 3983838 times.
✗ Branch 1 not taken.
3983706 tx->io_perf_start(&m_io_perf);
11727 }
11728
11729
1/2
✓ Branch 0 taken 7967523 times.
✗ Branch 1 not taken.
7967472 DBUG_RETURN(res);
11730 }
11731
11732 /**
11733 @note
11734 A quote from ha_innobase::start_stmt():
11735 <quote>
11736 MySQL calls this function at the start of each SQL statement inside LOCK
11737 TABLES. Inside LOCK TABLES the ::external_lock method does not work to
11738 mark SQL statement borders.
11739 </quote>
11740
11741 @return
11742 HA_EXIT_SUCCESS OK
11743 */
11744
11745 358 int ha_rocksdb::start_stmt(THD *const thd, thr_lock_type lock_type) {
11746
1/2
✓ Branch 0 taken 358 times.
✗ Branch 1 not taken.
358 DBUG_ENTER_FUNC();
11747
11748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 358 times.
358 assert(thd != nullptr);
11749
11750
1/2
✓ Branch 0 taken 358 times.
✗ Branch 1 not taken.
358 Rdb_transaction *const tx = get_or_create_tx(thd);
11751
1/2
✓ Branch 0 taken 358 times.
✗ Branch 1 not taken.
358 read_thd_vars(thd);
11752
1/2
✓ Branch 0 taken 358 times.
✗ Branch 1 not taken.
358 rocksdb_register_tx(ht, thd, tx);
11753
1/2
✓ Branch 0 taken 358 times.
✗ Branch 1 not taken.
358 tx->io_perf_start(&m_io_perf);
11754
11755
1/2
✓ Branch 0 taken 358 times.
✗ Branch 1 not taken.
358 DBUG_RETURN(HA_EXIT_SUCCESS);
11756 }
11757
11758 475697 rocksdb::Range get_range(uint32_t i,
11759 uchar buf[Rdb_key_def::INDEX_NUMBER_SIZE * 2],
11760 int offset1, int offset2) {
11761 475697 uchar *buf_begin = buf;
11762 475697 uchar *buf_end = buf + Rdb_key_def::INDEX_NUMBER_SIZE;
11763 475697 rdb_netbuf_store_index(buf_begin, i + offset1);
11764 475698 rdb_netbuf_store_index(buf_end, i + offset2);
11765
11766 return rocksdb::Range(
11767 475697 rocksdb::Slice((const char *)buf_begin, Rdb_key_def::INDEX_NUMBER_SIZE),
11768 951396 rocksdb::Slice((const char *)buf_end, Rdb_key_def::INDEX_NUMBER_SIZE));
11769 }
11770
11771 449296 static rocksdb::Range get_range(const Rdb_key_def &kd,
11772 uchar buf[Rdb_key_def::INDEX_NUMBER_SIZE * 2],
11773 int offset1, int offset2) {
11774 449296 return get_range(kd.get_index_number(), buf, offset1, offset2);
11775 }
11776
11777 449296 rocksdb::Range ha_rocksdb::get_range(
11778 const Rdb_key_def &kd, uchar buf[Rdb_key_def::INDEX_NUMBER_SIZE * 2]) {
11779
2/2
✓ Branch 0 taken 121777 times.
✓ Branch 1 taken 327519 times.
449296 if (kd.m_is_reverse_cf) {
11780 121777 return myrocks::get_range(kd, buf, 1, 0);
11781 } else {
11782 327519 return myrocks::get_range(kd, buf, 0, 1);
11783 }
11784 }
11785
11786 231 rocksdb::Range ha_rocksdb::get_range(
11787 const int i, uchar buf[Rdb_key_def::INDEX_NUMBER_SIZE * 2]) const {
11788 231 return get_range(*m_key_descr_arr[i], buf);
11789 }
11790
11791 /*
11792 This function is called with total_order_seek=true, but
11793 upper/lower bound setting is not necessary.
11794 Boundary set is useful when there is no matching key,
11795 but in drop_index_thread's case, it means index is marked as removed,
11796 so no further seek will happen for the index id.
11797 */
11798 26397 static bool is_myrocks_index_empty(rocksdb::ColumnFamilyHandle *cfh,
11799 const bool is_reverse_cf,
11800 const rocksdb::ReadOptions &read_opts,
11801 const uint index_id) {
11802 26397 bool index_removed = false;
11803 26397 uchar key_buf[Rdb_key_def::INDEX_NUMBER_SIZE] = {0};
11804 26397 rdb_netbuf_store_uint32(key_buf, index_id);
11805 const rocksdb::Slice key =
11806 26397 rocksdb::Slice(reinterpret_cast<char *>(key_buf), sizeof(key_buf));
11807
1/2
✓ Branch 0 taken 26397 times.
✗ Branch 1 not taken.
26397 std::unique_ptr<rocksdb::Iterator> it(rdb->NewIterator(read_opts, cfh));
11808
1/2
✓ Branch 0 taken 26397 times.
✗ Branch 1 not taken.
26397 rocksdb_smart_seek(is_reverse_cf, it.get(), key);
11809
3/4
✓ Branch 0 taken 26397 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16821 times.
✓ Branch 3 taken 9576 times.
26397 if (!it->Valid()) {
11810 16821 index_removed = true;
11811 } else {
11812
3/4
✓ Branch 0 taken 9576 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9541 times.
✓ Branch 3 taken 35 times.
9576 if (memcmp(it->key().data(), key_buf, Rdb_key_def::INDEX_NUMBER_SIZE)) {
11813 // Key does not have same prefix
11814 9541 index_removed = true;
11815 }
11816 }
11817 26397 return index_removed;
11818 26397 }
11819
11820 /*
11821 Drop index thread's main logic
11822 */
11823
11824 902 void Rdb_drop_index_thread::run() {
11825
2/4
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 902 times.
✗ Branch 3 not taken.
902 RDB_MUTEX_LOCK_CHECK(m_signal_mutex);
11826
1/2
✓ Branch 0 taken 902 times.
✗ Branch 1 not taken.
902 auto dict_manager_list = dict_manager.get_all_dict_manager_selector();
11827 for (;;) {
11828 // The stop flag might be set by shutdown command
11829 // after drop_index_thread releases signal_mutex
11830 // (i.e. while executing expensive Seek()). To prevent drop_index_thread
11831 // from entering long cond_timedwait, checking if stop flag
11832 // is true or not is needed, with drop_index_interrupt_mutex held.
11833
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12836 times.
12840 if (m_killed) {
11834 4 break;
11835 }
11836 timespec ts;
11837 12836 clock_gettime(CLOCK_REALTIME, &ts);
11838 12836 bool is_drop_index_empty = true;
11839
2/2
✓ Branch 0 taken 12944 times.
✓ Branch 1 taken 11217 times.
24161 for (Rdb_dict_manager *local_dict_manager : dict_manager_list) {
11840
3/4
✓ Branch 0 taken 12944 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1619 times.
✓ Branch 3 taken 11325 times.
12944 if (!local_dict_manager->is_drop_index_empty()) {
11841 1619 is_drop_index_empty = false;
11842 1619 break;
11843 }
11844 }
11845
2/2
✓ Branch 0 taken 11217 times.
✓ Branch 1 taken 1619 times.
12836 ts.tv_sec += is_drop_index_empty ? 24 * 60 * 60 // no filtering
11846 : 60; // filtering
11847
11848 const auto ret MY_ATTRIBUTE((__unused__)) =
11849
1/2
✓ Branch 0 taken 12800 times.
✗ Branch 1 not taken.
12836 mysql_cond_timedwait(&m_signal_cond, &m_signal_mutex, &ts);
11850
2/2
✓ Branch 0 taken 862 times.
✓ Branch 1 taken 11938 times.
12800 if (m_killed) {
11851 862 break;
11852 }
11853 // make sure, no program error is returned
11854
3/4
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 11889 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 49 times.
11938 assert(ret == 0 || ret == ETIMEDOUT);
11855
2/4
✓ Branch 0 taken 11938 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11938 times.
✗ Branch 3 not taken.
11938 RDB_MUTEX_UNLOCK_CHECK(m_signal_mutex);
11856
2/2
✓ Branch 0 taken 12049 times.
✓ Branch 1 taken 11938 times.
23987 for (Rdb_dict_manager *local_dict_manager : dict_manager_list) {
11857 12049 std::unordered_set<GL_INDEX_ID> indices;
11858
1/2
✓ Branch 0 taken 12049 times.
✗ Branch 1 not taken.
12049 local_dict_manager->get_ongoing_drop_indexes(&indices);
11859
2/2
✓ Branch 0 taken 11648 times.
✓ Branch 1 taken 401 times.
12049 if (!indices.empty()) {
11860 11648 std::unordered_set<GL_INDEX_ID> finished;
11861
1/2
✓ Branch 0 taken 11648 times.
✗ Branch 1 not taken.
11648 rocksdb::ReadOptions read_opts;
11862 11648 read_opts.total_order_seek = true; // disable bloom filter
11863
11864
2/2
✓ Branch 0 taken 26407 times.
✓ Branch 1 taken 11644 times.
38051 for (const auto d : indices) {
11865 26407 uint32 cf_flags = 0;
11866
2/4
✓ Branch 0 taken 26407 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 26407 times.
26407 if (!local_dict_manager->get_cf_flags(d.cf_id, &cf_flags)) {
11867 LogPluginErrMsg(ERROR_LEVEL, 0,
11868 "Failed to get column family flags "
11869 "from cf id %u. MyRocks data dictionary may "
11870 "get corrupted.",
11871 d.cf_id);
11872 abort();
11873 }
11874
11875 std::shared_ptr<rocksdb::ColumnFamilyHandle> cfh =
11876
1/2
✓ Branch 0 taken 26407 times.
✗ Branch 1 not taken.
26407 cf_manager.get_cf(d.cf_id);
11877
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26407 times.
26407 assert(cfh);
11878
11879
3/4
✓ Branch 0 taken 26407 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 26401 times.
26407 if (local_dict_manager->get_dropped_cf(d.cf_id)) {
11880
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 finished.insert(d);
11881 6 continue;
11882 }
11883
11884 26401 const bool is_reverse_cf = cf_flags & Rdb_key_def::REVERSE_CF_FLAG;
11885
11886 uchar buf[Rdb_key_def::INDEX_NUMBER_SIZE * 2];
11887
4/4
✓ Branch 0 taken 467 times.
✓ Branch 1 taken 25934 times.
✓ Branch 2 taken 467 times.
✓ Branch 3 taken 25934 times.
26401 rocksdb::Range range = get_range(
11888
1/2
✓ Branch 0 taken 26401 times.
✗ Branch 1 not taken.
26401 d.index_id, buf, is_reverse_cf ? 1 : 0, is_reverse_cf ? 0 : 1);
11889
11890 rocksdb::Status status = DeleteFilesInRange(
11891
2/4
✓ Branch 0 taken 26401 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26401 times.
✗ Branch 3 not taken.
26401 rdb->GetBaseDB(), cfh.get(), &range.start, &range.limit);
11892
2/4
✓ Branch 0 taken 26401 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 26401 times.
26401 if (!status.ok()) {
11893 if (status.IsIncomplete()) {
11894 continue;
11895 } else if (status.IsShutdownInProgress()) {
11896 break;
11897 }
11898 rdb_handle_io_error(status, RDB_IO_ERROR_BG_THREAD);
11899 }
11900
11901
1/2
✓ Branch 0 taken 26401 times.
✗ Branch 1 not taken.
52802 status = rdb->CompactRange(getCompactRangeOptions(), cfh.get(),
11902 26401 &range.start, &range.limit);
11903
3/4
✓ Branch 0 taken 26401 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 26397 times.
26401 if (!status.ok()) {
11904
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (status.IsIncomplete()) {
11905 continue;
11906
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 } else if (status.IsShutdownInProgress()) {
11907 4 break;
11908 }
11909 rdb_handle_io_error(status, RDB_IO_ERROR_BG_THREAD);
11910 }
11911
3/4
✓ Branch 0 taken 26397 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26362 times.
✓ Branch 3 taken 35 times.
26397 if (is_myrocks_index_empty(cfh.get(), is_reverse_cf, read_opts,
11912 26397 d.index_id)) {
11913
1/2
✓ Branch 0 taken 26362 times.
✗ Branch 1 not taken.
26362 finished.insert(d);
11914 }
11915
5/6
✓ Branch 0 taken 26397 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 26397 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 4 times.
26411 }
11916
11917
2/2
✓ Branch 0 taken 11630 times.
✓ Branch 1 taken 18 times.
11648 if (!finished.empty()) {
11918
1/2
✓ Branch 0 taken 11630 times.
✗ Branch 1 not taken.
11630 local_dict_manager->finish_drop_indexes(finished);
11919 }
11920 11648 }
11921
11922
10/18
✓ Branch 0 taken 12049 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 12005 times.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 44 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 44 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 44 times.
✓ Branch 14 taken 44 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 44 times.
✗ Branch 17 not taken.
12049 DBUG_EXECUTE_IF("rocksdb_drop_cf", {
11923 THD *thd = new THD();
11924 thd->thread_stack = reinterpret_cast<char *>(&(thd));
11925 thd->store_globals();
11926
11927 static const char act[] = "now wait_for ready_to_drop_cf";
11928 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
11929
11930 thd->restore_globals();
11931 delete thd;
11932 });
11933
11934 // Remove dropped column family
11935 // 1. Get all cf ids from ongoing_index_drop.
11936 // 2. Get all cf ids for cfs marked as dropped.
11937 // 3. If a cf id is in the list of ongoing_index_drop
11938 // , skip removing this cf. It will be removed later.
11939 // 4. If it is not, proceed to remove the cf.
11940 //
11941 // This should be under dict_manager lock
11942
11943 {
11944
1/2
✓ Branch 0 taken 12049 times.
✗ Branch 1 not taken.
12049 std::lock_guard<Rdb_dict_manager> dm_lock(*local_dict_manager);
11945 12049 std::unordered_set<uint32> dropped_cf_ids;
11946
1/2
✓ Branch 0 taken 12049 times.
✗ Branch 1 not taken.
12049 local_dict_manager->get_all_dropped_cfs(&dropped_cf_ids);
11947
11948
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 12011 times.
12049 if (!dropped_cf_ids.empty()) {
11949 38 std::unordered_set<GL_INDEX_ID> ongoing_drop_indices;
11950
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 local_dict_manager->get_ongoing_drop_indexes(&ongoing_drop_indices);
11951
11952 38 std::unordered_set<uint32> ongoing_drop_cf_ids;
11953
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 for (const auto index : ongoing_drop_indices) {
11954 ongoing_drop_cf_ids.insert(index.cf_id);
11955 }
11956
11957
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 38 times.
76 for (const auto cf_id : dropped_cf_ids) {
11958
2/4
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
38 if (ongoing_drop_cf_ids.find(cf_id) == ongoing_drop_cf_ids.end()) {
11959
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 cf_manager.remove_dropped_cf(local_dict_manager, rdb, cf_id);
11960 }
11961 }
11962 38 }
11963 12049 }
11964
11965
13/24
✓ Branch 0 taken 12049 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 12007 times.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 42 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 42 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 42 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 42 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 42 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 19 taken 42 times.
✓ Branch 20 taken 42 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 42 times.
✗ Branch 23 not taken.
12091 DBUG_EXECUTE_IF("rocksdb_drop_cf", {
11966 std::lock_guard<Rdb_dict_manager> dm_lock(*local_dict_manager);
11967 std::unordered_set<uint32> dropped_cf_ids;
11968 local_dict_manager->get_all_dropped_cfs(&dropped_cf_ids);
11969 if (dropped_cf_ids.empty()) {
11970 THD *thd = new THD();
11971 thd->thread_stack = reinterpret_cast<char *>(&(thd));
11972 thd->store_globals();
11973
11974 static const char act[] = "now signal drop_cf_done";
11975 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
11976
11977 thd->restore_globals();
11978 delete thd;
11979 }
11980 });
11981 12049 }
11982
2/4
✓ Branch 0 taken 11938 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11938 times.
✗ Branch 3 not taken.
11938 RDB_MUTEX_LOCK_CHECK(m_signal_mutex);
11983 11938 }
11984
11985
2/4
✓ Branch 0 taken 866 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 866 times.
✗ Branch 3 not taken.
866 RDB_MUTEX_UNLOCK_CHECK(m_signal_mutex);
11986 866 }
11987
11988 11983 Rdb_tbl_def *ha_rocksdb::get_table_if_exists(const char *const tablename) {
11989
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11983 times.
11983 assert(tablename != nullptr);
11990
11991 11983 std::string str;
11992
3/6
✓ Branch 0 taken 11983 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11984 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11984 times.
11983 if (rdb_normalize_tablename(tablename, &str) != HA_EXIT_SUCCESS) {
11993 // We were not passed table name?
11994 assert(0);
11995 return nullptr;
11996 }
11997
11998
1/2
✓ Branch 0 taken 11983 times.
✗ Branch 1 not taken.
11984 return ddl_manager.find(str);
11999 11983 }
12000
12001 /*
12002 Overload func for delete table ---it deletes table meta data in data
12003 dictionary immediately and delete real data in background thread(async)
12004
12005 @param tbl IN MyRocks table definition
12006
12007 @return
12008 HA_EXIT_SUCCESS OK
12009 other HA_ERR error code (can be SE-specific)
12010 */
12011 14461 int ha_rocksdb::delete_table(Rdb_tbl_def *const tbl) {
12012
1/2
✓ Branch 0 taken 14463 times.
✗ Branch 1 not taken.
14461 DBUG_ENTER_FUNC();
12013
12014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14463 times.
14463 assert(tbl != nullptr);
12015
3/4
✓ Branch 0 taken 2599 times.
✓ Branch 1 taken 11864 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2599 times.
14463 assert(m_tbl_def == nullptr || m_tbl_def == tbl);
12016
1/2
✓ Branch 0 taken 14461 times.
✗ Branch 1 not taken.
14463 uint table_default_cf_id = tbl->m_key_descr_arr[0]->get_gl_index_id().cf_id;
12017 auto local_dict_manager =
12018
1/2
✓ Branch 0 taken 14463 times.
✗ Branch 1 not taken.
14461 dict_manager.get_dict_manager_selector_non_const(table_default_cf_id);
12019
1/2
✓ Branch 0 taken 14462 times.
✗ Branch 1 not taken.
14463 const std::unique_ptr<rocksdb::WriteBatch> wb = local_dict_manager->begin();
12020 14462 rocksdb::WriteBatch *const batch = wb.get();
12021
12022
6/10
✓ Branch 0 taken 14462 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 14456 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 6 times.
14462 DBUG_EXECUTE_IF("rocksdb_before_delete_table", {
12023 static constexpr char act[] =
12024 "now signal ready_to_mark_cf_dropped_before_delete_table wait_for "
12025 "mark_cf_dropped_done_before_delete_table";
12026 assert(!debug_sync_set_action(ha_thd(), STRING_WITH_LEN(act)));
12027 });
12028
12029 {
12030
1/2
✓ Branch 0 taken 14463 times.
✗ Branch 1 not taken.
14462 std::lock_guard<Rdb_dict_manager> dm_lock(*local_dict_manager);
12031
1/2
✓ Branch 0 taken 14463 times.
✗ Branch 1 not taken.
14463 local_dict_manager->add_drop_table(tbl->m_key_descr_arr, tbl->m_key_count,
12032 batch);
12033
12034 /*
12035 Remove the table entry in data dictionary (this will also remove it from
12036 the persistent data dictionary).
12037 */
12038
1/2
✓ Branch 0 taken 14463 times.
✗ Branch 1 not taken.
14463 ddl_manager.remove(tbl, batch, table_default_cf_id, true);
12039
12040
1/2
✓ Branch 0 taken 14463 times.
✗ Branch 1 not taken.
14463 int err = local_dict_manager->commit(batch);
12041
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14463 times.
14463 if (err) {
12042 DBUG_RETURN(err);
12043 }
12044
1/2
✓ Branch 0 taken 14463 times.
✗ Branch 1 not taken.
14463 }
12045
12046
6/10
✓ Branch 0 taken 14463 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 14457 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 6 times.
14463 DBUG_EXECUTE_IF("rocksdb_after_delete_table", {
12047 static constexpr char act[] =
12048 "now signal ready_to_mark_cf_dropped_after_delete_table "
12049 "wait_for mark_cf_dropped_done_after_delete_table";
12050 assert(!debug_sync_set_action(ha_thd(), STRING_WITH_LEN(act)));
12051 });
12052
12053
1/2
✓ Branch 0 taken 14463 times.
✗ Branch 1 not taken.
14463 rdb_drop_idx_thread.signal();
12054 // avoid dangling pointer
12055 14463 m_tbl_def = nullptr;
12056
1/2
✓ Branch 0 taken 14463 times.
✗ Branch 1 not taken.
14463 DBUG_RETURN(HA_EXIT_SUCCESS);
12057 14463 }
12058
12059 /*
12060 Note: the following function is called when the table is not open. That is,
12061 this->table==nullptr, pk_key_descr==nullptr, etc.
12062
12063 tablename points to line in form "./dbname/tablename".
12064
12065 @return
12066 HA_EXIT_SUCCESS OK
12067 other HA_ERR error code (can be SE-specific)
12068 */
12069
12070 11983 int ha_rocksdb::delete_table(const char *const tablename,
12071 const dd::Table *table_def
12072 MY_ATTRIBUTE((__unused__))) {
12073
1/2
✓ Branch 0 taken 11984 times.
✗ Branch 1 not taken.
11983 DBUG_ENTER_FUNC();
12074
12075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11984 times.
11984 assert(tablename != nullptr);
12076
12077 /* Find the table in the hash */
12078
1/2
✓ Branch 0 taken 11983 times.
✗ Branch 1 not taken.
11984 Rdb_tbl_def *const tbl = get_table_if_exists(tablename);
12079
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11971 times.
11983 if (!tbl) {
12080
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
12081 }
12082
12083
2/4
✓ Branch 0 taken 11972 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11972 times.
✗ Branch 3 not taken.
11971 DBUG_RETURN(delete_table(tbl));
12084 }
12085
12086 /**
12087 @return
12088 HA_EXIT_SUCCESS OK
12089 other HA_ERR error code (cannot be SE-specific)
12090 */
12091 5128 int ha_rocksdb::rename_table(
12092 const char *const from, const char *const to,
12093 const dd::Table *from_table_def MY_ATTRIBUTE((__unused__)),
12094 dd::Table *to_table_def MY_ATTRIBUTE((__unused__))) {
12095
1/2
✓ Branch 0 taken 5128 times.
✗ Branch 1 not taken.
5128 DBUG_ENTER_FUNC();
12096
12097 5128 std::string from_str;
12098 5128 std::string to_str;
12099 5128 std::string from_db;
12100 5128 std::string to_db;
12101 int rc;
12102
12103
4/6
✓ Branch 0 taken 5128 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5128 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2509 times.
✓ Branch 5 taken 2619 times.
5128 if (rdb_is_tablename_normalized(from)) {
12104
1/2
✓ Branch 0 taken 2509 times.
✗ Branch 1 not taken.
2509 from_str = from;
12105 } else {
12106
2/4
✓ Branch 0 taken 2619 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2619 times.
✗ Branch 3 not taken.
2619 rc = rdb_normalize_tablename(from, &from_str);
12107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2619 times.
2619 if (rc != HA_EXIT_SUCCESS) {
12108 DBUG_RETURN(rc);
12109 }
12110 }
12111
12112
1/2
✓ Branch 0 taken 5128 times.
✗ Branch 1 not taken.
5128 rc = rdb_split_normalized_tablename(from_str, &from_db);
12113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5128 times.
5128 if (rc != HA_EXIT_SUCCESS) {
12114 DBUG_RETURN(rc);
12115 }
12116
12117
4/6
✓ Branch 0 taken 5128 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5128 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2509 times.
✓ Branch 5 taken 2619 times.
5128 if (rdb_is_tablename_normalized(to)) {
12118
1/2
✓ Branch 0 taken 2509 times.
✗ Branch 1 not taken.
2509 to_str = to;
12119 } else {
12120
2/4
✓ Branch 0 taken 2619 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2619 times.
✗ Branch 3 not taken.
2619 rc = rdb_normalize_tablename(to, &to_str);
12121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2619 times.
2619 if (rc != HA_EXIT_SUCCESS) {
12122 DBUG_RETURN(rc);
12123 }
12124 }
12125
12126
1/2
✓ Branch 0 taken 5128 times.
✗ Branch 1 not taken.
5128 rc = rdb_split_normalized_tablename(to_str, &to_db);
12127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5128 times.
5128 if (rc != HA_EXIT_SUCCESS) {
12128 DBUG_RETURN(rc);
12129 }
12130
12131 // If the user changed the database part of the name then validate that the
12132 // 'to' database exists.
12133
5/8
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 5042 times.
✓ Branch 2 taken 86 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 86 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5128 times.
5128 if (from_db != to_db && !rdb_database_exists(to_db)) {
12134 // If we return a RocksDB specific error code here we get
12135 // "error: 206 - Unknown error 206". InnoDB gets
12136 // "error -1 - Unknown error -1" so let's match them.
12137 DBUG_RETURN(-1);
12138 }
12139
12140
4/6
✓ Branch 0 taken 5128 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 5125 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
5128 DBUG_EXECUTE_IF("gen_sql_table_name", to_str = to_str + "_rdb_only";);
12141
12142 auto local_dict_manager =
12143
1/2
✓ Branch 0 taken 5128 times.
✗ Branch 1 not taken.
5128 dict_manager.get_dict_manager_selector_non_const(is_tmp_table(from_str));
12144
12145
1/2
✓ Branch 0 taken 5128 times.
✗ Branch 1 not taken.
5128 const std::unique_ptr<rocksdb::WriteBatch> wb = local_dict_manager->begin();
12146 5128 rocksdb::WriteBatch *const batch = wb.get();
12147
12148 // rename table is under dict_manager lock, and the cfs used
12149 // by indices of this table cannot be dropped during the process.
12150
1/2
✓ Branch 0 taken 5128 times.
✗ Branch 1 not taken.
5128 std::lock_guard<Rdb_dict_manager> dm_lock(*local_dict_manager);
12151
2/4
✓ Branch 0 taken 5128 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5128 times.
5128 if (ddl_manager.rename(from_str, to_str, batch)) {
12152 rc = HA_ERR_ROCKSDB_INVALID_TABLE;
12153 } else {
12154
1/2
✓ Branch 0 taken 5128 times.
✗ Branch 1 not taken.
5128 rc = local_dict_manager->commit(batch);
12155 }
12156
1/2
✓ Branch 0 taken 5128 times.
✗ Branch 1 not taken.
5128 DBUG_RETURN(rc);
12157 5128 }
12158
12159 /**
12160 check_if_incompatible_data() called if ALTER TABLE can't detect otherwise
12161 if new and old definition are compatible
12162
12163 @details If there are no other explicit signs like changed number of
12164 fields this function will be called by compare_tables()
12165 (sql/sql_tables.cc) to decide should we rewrite whole table or only .frm
12166 file.
12167
12168 */
12169
12170 bool ha_rocksdb::check_if_incompatible_data(HA_CREATE_INFO *const info,
12171 uint table_changes) {
12172 DBUG_ENTER_FUNC();
12173
12174 assert(info != nullptr);
12175
12176 // this function is needed only for online alter-table
12177 DBUG_RETURN(COMPATIBLE_DATA_NO);
12178 }
12179
12180 /**
12181 @return
12182 HA_EXIT_SUCCESS OK
12183 */
12184 32156675 int ha_rocksdb::extra(enum ha_extra_function operation) {
12185
1/2
✓ Branch 0 taken 32157674 times.
✗ Branch 1 not taken.
32156675 DBUG_ENTER_FUNC();
12186
12187
5/6
✓ Branch 0 taken 128323 times.
✓ Branch 1 taken 128287 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 237 times.
✓ Branch 4 taken 4080790 times.
✓ Branch 5 taken 27820037 times.
32157674 switch (operation) {
12188 128323 case HA_EXTRA_KEYREAD:
12189 128323 m_keyread_only = true;
12190 128323 break;
12191 128287 case HA_EXTRA_NO_KEYREAD:
12192 128287 m_keyread_only = false;
12193 128287 break;
12194 case HA_EXTRA_FLUSH:
12195 /*
12196 If the table has blobs, then they are part of m_retrieved_record.
12197 This call invalidates them.
12198 */
12199 m_retrieved_record.Reset();
12200 m_dup_key_retrieved_record.Reset();
12201 break;
12202 237 case HA_EXTRA_INSERT_WITH_UPDATE:
12203 // INSERT ON DUPLICATE KEY UPDATE
12204
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 27 times.
237 if (rocksdb_enable_insert_with_update_caching) {
12205 210 m_insert_with_update = true;
12206 }
12207 237 break;
12208 4080790 case HA_EXTRA_NO_IGNORE_DUP_KEY:
12209 // PAIRED with HA_EXTRA_INSERT_WITH_UPDATE or HA_EXTRA_WRITE_CAN_REPLACE
12210 // that indicates the end of REPLACE / INSERT ON DUPLICATE KEY
12211 4080790 m_insert_with_update = false;
12212 4080790 break;
12213
12214 27820037 default:
12215 27820037 break;
12216 }
12217
12218
1/2
✓ Branch 0 taken 32157745 times.
✗ Branch 1 not taken.
32157674 DBUG_RETURN(HA_EXIT_SUCCESS);
12219 }
12220
12221 /*
12222 Given a starting key and an ending key, estimate the number of rows that
12223 will exist between the two keys.
12224 */
12225 227285 ha_rows ha_rocksdb::records_in_range(uint inx, key_range *const min_key,
12226 key_range *const max_key) {
12227
1/2
✓ Branch 0 taken 227285 times.
✗ Branch 1 not taken.
227285 DBUG_ENTER_FUNC();
12228
12229
2/4
✓ Branch 0 taken 227285 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 227285 times.
✗ Branch 3 not taken.
227285 ha_rows ret = THDVAR(ha_thd(), records_in_range);
12230
2/2
✓ Branch 0 taken 28898 times.
✓ Branch 1 taken 198387 times.
227285 if (ret) {
12231
1/2
✓ Branch 0 taken 28898 times.
✗ Branch 1 not taken.
28898 DBUG_RETURN(ret);
12232 }
12233
2/2
✓ Branch 0 taken 122666 times.
✓ Branch 1 taken 75721 times.
198387 if (table->force_index) {
12234
2/4
✓ Branch 0 taken 122666 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 122666 times.
✗ Branch 3 not taken.
122666 const ha_rows force_rows = THDVAR(ha_thd(), force_index_records_in_range);
12235
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 122663 times.
122666 if (force_rows) {
12236
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(force_rows);
12237 }
12238 }
12239
12240 198384 const Rdb_key_def &kd = *m_key_descr_arr[inx];
12241
12242 198384 auto disk_size = kd.m_stats.m_actual_disk_size;
12243
2/2
✓ Branch 0 taken 8707 times.
✓ Branch 1 taken 189677 times.
198384 if (disk_size == 0) disk_size = kd.m_stats.m_data_size;
12244 198384 auto rows = kd.m_stats.m_rows;
12245
3/4
✓ Branch 0 taken 189677 times.
✓ Branch 1 taken 8707 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 189677 times.
198384 if (rows == 0 || disk_size == 0) {
12246 8707 rows = 1;
12247 8707 disk_size = ROCKSDB_ASSUMED_KEY_VALUE_DISK_SIZE;
12248 }
12249 198384 ulonglong total_size = 0;
12250 198384 ulonglong total_row = 0;
12251
1/2
✓ Branch 0 taken 198384 times.
✗ Branch 1 not taken.
198384 records_in_range_internal(inx, min_key, max_key, disk_size, rows, &total_size,
12252 &total_row);
12253 198384 ret = total_row;
12254 /*
12255 GetApproximateSizes() gives estimates so ret might exceed stats.records.
12256 MySQL then decides to use full index scan rather than range scan, which
12257 is not efficient for most cases.
12258 To prevent this, changing estimated records slightly smaller than
12259 stats.records.
12260 */
12261
2/2
✓ Branch 0 taken 2446 times.
✓ Branch 1 taken 195938 times.
198384 if (ret >= stats.records) {
12262 2446 ret = stats.records * 0.99;
12263 }
12264
12265
2/2
✓ Branch 0 taken 3039 times.
✓ Branch 1 taken 195345 times.
198384 if (rocksdb_debug_optimizer_n_rows > 0) {
12266 3039 ret = rocksdb_debug_optimizer_n_rows;
12267
2/2
✓ Branch 0 taken 137322 times.
✓ Branch 1 taken 58023 times.
195345 } else if (ret == 0) {
12268 137322 ret = 1;
12269 }
12270
12271
1/2
✓ Branch 0 taken 198384 times.
✗ Branch 1 not taken.
198384 DBUG_RETURN(ret);
12272 }
12273
12274 198384 void ha_rocksdb::records_in_range_internal(uint inx, key_range *const min_key,
12275 key_range *const max_key,
12276 int64 disk_size, int64 rows,
12277 ulonglong *total_size,
12278 ulonglong *row_count) {
12279
1/2
✓ Branch 0 taken 198384 times.
✗ Branch 1 not taken.
198384 DBUG_ENTER_FUNC();
12280
12281 198384 const Rdb_key_def &kd = *m_key_descr_arr[inx];
12282
12283 198384 uint size1 = 0;
12284
2/2
✓ Branch 0 taken 197986 times.
✓ Branch 1 taken 398 times.
198384 if (min_key) {
12285 395972 size1 = kd.pack_index_tuple(table, m_pack_buffer, m_sk_packed_tuple,
12286
1/2
✓ Branch 0 taken 197986 times.
✗ Branch 1 not taken.
197986 min_key->key, min_key->keypart_map);
12287
1/2
✓ Branch 0 taken 197986 times.
✗ Branch 1 not taken.
197986 if (min_key->flag == HA_READ_PREFIX_LAST_OR_PREV ||
12288
1/2
✓ Branch 0 taken 197986 times.
✗ Branch 1 not taken.
197986 min_key->flag == HA_READ_PREFIX_LAST ||
12289
2/2
✓ Branch 0 taken 778 times.
✓ Branch 1 taken 197208 times.
197986 min_key->flag == HA_READ_AFTER_KEY) {
12290
1/2
✓ Branch 0 taken 778 times.
✗ Branch 1 not taken.
778 kd.successor(m_sk_packed_tuple, size1);
12291 }
12292 } else {
12293 398 kd.get_infimum_key(m_sk_packed_tuple, &size1);
12294 }
12295
12296 198384 uint size2 = 0;
12297
2/2
✓ Branch 0 taken 196700 times.
✓ Branch 1 taken 1684 times.
198384 if (max_key) {
12298 393400 size2 = kd.pack_index_tuple(table, m_pack_buffer, m_sk_packed_tuple_old,
12299
1/2
✓ Branch 0 taken 196700 times.
✗ Branch 1 not taken.
196700 max_key->key, max_key->keypart_map);
12300
1/2
✓ Branch 0 taken 196700 times.
✗ Branch 1 not taken.
196700 if (max_key->flag == HA_READ_PREFIX_LAST_OR_PREV ||
12301
1/2
✓ Branch 0 taken 196700 times.
✗ Branch 1 not taken.
196700 max_key->flag == HA_READ_PREFIX_LAST ||
12302
2/2
✓ Branch 0 taken 195965 times.
✓ Branch 1 taken 735 times.
196700 max_key->flag == HA_READ_AFTER_KEY) {
12303
1/2
✓ Branch 0 taken 195965 times.
✗ Branch 1 not taken.
195965 kd.successor(m_sk_packed_tuple_old, size2);
12304 }
12305 } else {
12306 1684 kd.get_supremum_key(m_sk_packed_tuple_old, &size2);
12307 }
12308
12309 198384 const rocksdb::Slice slice1((const char *)m_sk_packed_tuple, size1);
12310 198384 const rocksdb::Slice slice2((const char *)m_sk_packed_tuple_old, size2);
12311
12312 // It's possible to get slice1 == slice2 for a non-inclusive range with the
12313 // right bound being successor() of the left one, e.g. "t.key>10 AND t.key<11"
12314
3/4
✓ Branch 0 taken 198384 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 198381 times.
198384 if (slice1.compare(slice2) >= 0) {
12315 // It's not possible to get slice2 > slice1
12316
2/8
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 assert(!min_key || !max_key || slice1.compare(slice2) == 0);
12317
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_VOID_RETURN;
12318 }
12319
12320 198381 rocksdb::Range r(kd.m_is_reverse_cf ? slice2 : slice1,
12321
4/4
✓ Branch 0 taken 121311 times.
✓ Branch 1 taken 77070 times.
✓ Branch 2 taken 121311 times.
✓ Branch 3 taken 77070 times.
198381 kd.m_is_reverse_cf ? slice1 : slice2);
12322
12323 198381 uint64_t sz = 0;
12324
12325 #pragma GCC diagnostic push
12326 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
12327 // Getting statistics, including from Memtables
12328 198381 rocksdb::DB::SizeApproximationFlags include_flags =
12329 rocksdb::DB::SizeApproximationFlags::INCLUDE_FILES;
12330
1/2
✓ Branch 0 taken 198381 times.
✗ Branch 1 not taken.
198381 rdb->GetApproximateSizes(kd.get_cf(), &r, 1, &sz, include_flags);
12331 198381 *row_count = rows * ((double)sz / (double)disk_size);
12332 198381 *total_size = sz;
12333 uint64_t memTableCount;
12334
1/2
✓ Branch 0 taken 198381 times.
✗ Branch 1 not taken.
198381 rdb->GetApproximateMemTableStats(kd.get_cf(), r, &memTableCount, &sz);
12335 198381 *row_count += memTableCount;
12336 198381 *total_size += sz;
12337
1/2
✓ Branch 0 taken 198381 times.
✗ Branch 1 not taken.
198381 DBUG_VOID_RETURN;
12338 }
12339
12340 2289 void ha_rocksdb::update_create_info(HA_CREATE_INFO *const create_info) {
12341
1/2
✓ Branch 0 taken 2289 times.
✗ Branch 1 not taken.
2289 DBUG_ENTER_FUNC();
12342
12343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2289 times.
2289 assert(create_info != nullptr);
12344
12345
2/2
✓ Branch 0 taken 2232 times.
✓ Branch 1 taken 57 times.
2289 if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) {
12346 2232 create_info->auto_increment_value = m_tbl_def->m_auto_incr_val;
12347 }
12348
12349
1/2
✓ Branch 0 taken 2289 times.
✗ Branch 1 not taken.
4578 DBUG_VOID_RETURN;
12350 }
12351
12352 /**
12353 @brief
12354 Doing manual compaction on OPTIMIZE TABLE in RocksDB.
12355 Compaction itself is executed by background thread in RocksDB, but
12356 CompactRange() waits until compaction completes so this function
12357 may take a long time.
12358 Since RocksDB dataset is allocated per index id, OPTIMIZE TABLE
12359 triggers manual compaction for all indexes of the table.
12360 @details
12361 Compaction range is from the beginning of the index id to
12362 the first row of the next index id. When using reverse order
12363 column family, the first row of the next index id should be
12364 the last row of the previous index id.
12365
12366 @return
12367 HA_ADMIN_OK OK
12368 other HA_ADMIN error code
12369 */
12370 81 int ha_rocksdb::optimize(THD *const thd, HA_CHECK_OPT *const check_opt) {
12371
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 DBUG_ENTER_FUNC();
12372
12373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
81 assert(thd != nullptr);
12374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
81 assert(check_opt != nullptr);
12375
12376
2/2
✓ Branch 0 taken 231 times.
✓ Branch 1 taken 78 times.
309 for (uint i = 0; i < table->s->keys; i++) {
12377 uchar buf[Rdb_key_def::INDEX_NUMBER_SIZE * 2];
12378
1/2
✓ Branch 0 taken 231 times.
✗ Branch 1 not taken.
231 auto range = get_range(i, buf);
12379 231 const rocksdb::Status s = rdb->CompactRange(getCompactRangeOptions(),
12380 231 m_key_descr_arr[i]->get_cf(),
12381
1/2
✓ Branch 0 taken 231 times.
✗ Branch 1 not taken.
462 &range.start, &range.limit);
12382
3/4
✓ Branch 0 taken 231 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 228 times.
231 if (!s.ok()) {
12383
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 DBUG_RETURN(rdb_error_to_mysql(s));
12384 }
12385
2/2
✓ Branch 0 taken 228 times.
✓ Branch 1 taken 3 times.
231 }
12386
12387
1/2
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
78 DBUG_RETURN(HA_EXIT_SUCCESS);
12388 }
12389
12390 908 static void init_stats(
12391 const std::unordered_map<GL_INDEX_ID, std::shared_ptr<const Rdb_key_def>>
12392 &to_recalc,
12393 std::unordered_map<GL_INDEX_ID, Rdb_index_stats> *stats) {
12394
2/2
✓ Branch 0 taken 2916 times.
✓ Branch 1 taken 907 times.
3823 for (const auto &it : to_recalc) {
12395 2916 const GL_INDEX_ID index_id = it.first;
12396 2916 auto &kd = it.second;
12397
12398
1/2
✓ Branch 0 taken 2916 times.
✗ Branch 1 not taken.
2916 (*stats).emplace(index_id, Rdb_index_stats(index_id));
12399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2916 times.
2916 assert(kd->get_key_parts() > 0);
12400
2/4
✓ Branch 0 taken 2916 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2915 times.
✗ Branch 3 not taken.
2916 (*stats)[index_id].m_distinct_keys_per_prefix.resize(kd->get_key_parts());
12401 }
12402 907 }
12403
12404 /**
12405 Calculate the following index stats for all indexes of a table:
12406 number of rows, file size, and cardinality. It adopts an index
12407 scan approach using rocksdb::Iterator. Sampling is used to
12408 accelerate the scan.
12409 **/
12410 442 static int calculate_cardinality_table_scan(
12411 const std::unordered_map<GL_INDEX_ID, std::shared_ptr<const Rdb_key_def>>
12412 &to_recalc,
12413 std::unordered_map<GL_INDEX_ID, Rdb_index_stats> *stats,
12414 table_cardinality_scan_type scan_type, uint64_t max_num_rows_scanned,
12415 std::atomic<THD::killed_state> *killed) {
12416
1/2
✓ Branch 0 taken 442 times.
✗ Branch 1 not taken.
442 DBUG_ENTER_FUNC();
12417
12418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 442 times.
442 assert(scan_type != SCAN_TYPE_NONE);
12419
1/2
✓ Branch 0 taken 442 times.
✗ Branch 1 not taken.
442 init_stats(to_recalc, stats);
12420
12421
1/2
✓ Branch 0 taken 442 times.
✗ Branch 1 not taken.
442 auto read_opts = rocksdb::ReadOptions();
12422 442 read_opts.fill_cache = false;
12423
2/2
✓ Branch 0 taken 393 times.
✓ Branch 1 taken 49 times.
442 if (scan_type == SCAN_TYPE_MEMTABLE_ONLY) {
12424 393 read_opts.read_tier = rocksdb::ReadTier::kMemtableTier;
12425 } else {
12426 49 read_opts.total_order_seek = true;
12427 }
12428
12429
1/2
✓ Branch 0 taken 442 times.
✗ Branch 1 not taken.
442 Rdb_tbl_card_coll cardinality_collector(rocksdb_table_stats_sampling_pct);
12430
12431
2/2
✓ Branch 0 taken 1425 times.
✓ Branch 1 taken 442 times.
1867 for (const auto &it_kd : to_recalc) {
12432 1425 const GL_INDEX_ID index_id = it_kd.first;
12433
12434
2/4
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1425 times.
1425 if (!ddl_manager.safe_find(index_id)) {
12435 // If index id is not in ddl manager, then it has been dropped.
12436 // Skip scanning index
12437 continue;
12438 }
12439
12440 1425 const std::shared_ptr<const Rdb_key_def> &kd = it_kd.second;
12441
2/4
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1425 times.
1425 assert(index_id == kd->get_gl_index_id());
12442
2/4
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1425 times.
✗ Branch 3 not taken.
1425 Rdb_index_stats &stat = (*stats)[kd->get_gl_index_id()];
12443
12444 uchar r_buf[Rdb_key_def::INDEX_NUMBER_SIZE * 2];
12445
1/2
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
1425 auto r = ha_rocksdb::get_range(*kd, r_buf);
12446 uint64_t memtableCount;
12447 uint64_t memtableSize;
12448
1/2
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
1425 rdb->GetApproximateMemTableStats(kd->get_cf(), r, &memtableCount,
12449 &memtableSize);
12450
12451
2/2
✓ Branch 0 taken 1206 times.
✓ Branch 1 taken 219 times.
1425 if (scan_type == SCAN_TYPE_MEMTABLE_ONLY &&
12452
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1206 times.
1206 memtableCount < (uint64_t)stat.m_rows / 10) {
12453 // skip tables that already have enough stats from SST files to reduce
12454 // overhead and avoid degradation of big tables stats by sampling from
12455 // relatively tiny (less than 10% of full data set) memtable dataset
12456 continue;
12457 }
12458
12459 // Set memtable count to row count
12460 1425 stat.m_rows = memtableCount;
12461
12462
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 1206 times.
1425 if (scan_type == SCAN_TYPE_FULL_TABLE) {
12463 // Set memtable size to file size
12464 219 stat.m_actual_disk_size = memtableSize;
12465 }
12466
12467 std::unique_ptr<rocksdb::Iterator> it = std::unique_ptr<rocksdb::Iterator>(
12468
1/2
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
1425 rdb->NewIterator(read_opts, kd->get_cf()));
12469 rocksdb::Slice first_index_key((const char *)r_buf,
12470 1425 Rdb_key_def::INDEX_NUMBER_SIZE);
12471
12472 // Reset m_last_key for new index
12473
1/2
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
1425 cardinality_collector.Reset();
12474 1425 uint64_t rows_scanned = 0ul;
12475
5/8
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10458395 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10459820 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10458696 times.
✓ Branch 7 taken 1124 times.
10459819 for (it->Seek(first_index_key); is_valid_iterator(it.get()); it->Next()) {
12476
3/6
✓ Branch 0 taken 10458696 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10458696 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 10458696 times.
10458696 if (killed && *killed) {
12477 LogPluginErrMsg(
12478 INFORMATION_LEVEL, 0,
12479 "Index stats calculation for index %s with id (%u,%u) is "
12480 "terminated",
12481 kd->get_name().c_str(), stat.m_gl_index_id.cf_id,
12482 stat.m_gl_index_id.index_id);
12483 DBUG_RETURN(HA_EXIT_FAILURE);
12484 }
12485
12486
1/2
✓ Branch 0 taken 10458696 times.
✗ Branch 1 not taken.
10458696 const rocksdb::Slice key = it->key();
12487
12488
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 692784 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
692784 if ((scan_type == SCAN_TYPE_FULL_TABLE && max_num_rows_scanned > 0 &&
12489
4/4
✓ Branch 0 taken 692784 times.
✓ Branch 1 taken 9765912 times.
✓ Branch 2 taken 301 times.
✓ Branch 3 taken 10458395 times.
20917392 rows_scanned >= max_num_rows_scanned) ||
12490
2/2
✓ Branch 0 taken 301 times.
✓ Branch 1 taken 10458395 times.
10458696 !kd->covers_key(key)) {
12491 301 break; // end of this index
12492 }
12493
12494
1/2
✓ Branch 0 taken 10458394 times.
✗ Branch 1 not taken.
10458395 cardinality_collector.ProcessKey(key, kd.get(), &stat);
12495 10458394 rows_scanned++;
12496 }
12497
12498 cardinality_collector
12499
1/2
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
1425 .Reset(); /* reset m_last_key for each key definition */
12500
1/2
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
1425 cardinality_collector.SetCardinality(&stat);
12501
1/2
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
1425 cardinality_collector.AdjustStats(&stat);
12502
12503
12/20
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1419 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✗ Branch 19 not taken.
1425 DBUG_EXECUTE_IF("rocksdb_calculate_stats", {
12504 if (kd->get_name() == "secondary_key") {
12505 THD *thd = new THD();
12506 thd->thread_stack = reinterpret_cast<char *>(&thd);
12507 thd->store_globals();
12508
12509 static constexpr char act[] =
12510 "now signal ready_to_drop_index wait_for ready_to_save_index_stats";
12511 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
12512
12513 thd->restore_globals();
12514 delete thd;
12515 }
12516 });
12517
1/2
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
1425 }
12518
12519
1/2
✓ Branch 0 taken 442 times.
✗ Branch 1 not taken.
442 DBUG_RETURN(HA_EXIT_SUCCESS);
12520 442 }
12521
12522 49 static void reset_cardinality(
12523 std::unordered_map<GL_INDEX_ID, Rdb_index_stats> *stats) {
12524
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 49 times.
268 for (auto &src : *stats) {
12525 219 Rdb_index_stats &stat = src.second;
12526
1/2
✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
219 stat.reset_cardinality();
12527 }
12528 49 }
12529
12530 442 static void merge_stats(
12531 const std::unordered_map<GL_INDEX_ID, std::shared_ptr<const Rdb_key_def>>
12532 &to_recalc,
12533 std::unordered_map<GL_INDEX_ID, Rdb_index_stats> *stats,
12534 const std::unordered_map<GL_INDEX_ID, Rdb_index_stats> &card_stats) {
12535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 442 times.
442 assert(stats->size() == card_stats.size());
12536
12537
2/2
✓ Branch 0 taken 1425 times.
✓ Branch 1 taken 442 times.
1867 for (auto &src : *stats) {
12538 1425 auto index_id = src.first;
12539 1425 Rdb_index_stats &stat = src.second;
12540
1/2
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
1425 auto it = card_stats.find(index_id);
12541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1425 times.
1425 assert(it != card_stats.end());
12542
12543
1/2
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
1425 auto it_index = to_recalc.find(index_id);
12544
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1425 times.
1425 assert(it_index != to_recalc.end());
12545
1/2
✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
1425 stat.merge(it->second, true, it_index->second->max_storage_fmt_length());
12546 }
12547 442 }
12548
12549 static void adjust_cardinality(
12550 std::unordered_map<GL_INDEX_ID, Rdb_index_stats> *stats,
12551 table_cardinality_scan_type scan_type, uint64_t max_num_rows_scanned) {
12552 assert(scan_type == SCAN_TYPE_FULL_TABLE);
12553 assert(max_num_rows_scanned > 0);
12554
12555 for (auto &src : *stats) {
12556 Rdb_index_stats &stat = src.second;
12557 if ((uint64_t)stat.m_rows > max_num_rows_scanned) {
12558 stat.adjust_cardinality(stat.m_rows / max_num_rows_scanned);
12559 }
12560 #ifndef NDEBUG
12561 for (size_t i = 0; i < stat.m_distinct_keys_per_prefix.size(); i++) {
12562 assert(stat.m_distinct_keys_per_prefix[i] <= stat.m_rows);
12563 }
12564 #endif
12565 }
12566 }
12567
12568 466 static int read_stats_from_ssts(
12569 const std::unordered_map<GL_INDEX_ID, std::shared_ptr<const Rdb_key_def>>
12570 &to_recalc,
12571 std::unordered_map<GL_INDEX_ID, Rdb_index_stats> *stats) {
12572
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 DBUG_ENTER_FUNC();
12573
12574
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 init_stats(to_recalc, stats);
12575
12576 // find per column family key ranges which need to be queried
12577 std::unordered_map<rocksdb::ColumnFamilyHandle *, std::vector<rocksdb::Range>>
12578 466 ranges;
12579
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 std::vector<uchar> buf(to_recalc.size() * 2 * Rdb_key_def::INDEX_NUMBER_SIZE);
12580
12581 466 uchar *bufp = buf.data();
12582
2/2
✓ Branch 0 taken 1491 times.
✓ Branch 1 taken 466 times.
1957 for (const auto &it : to_recalc) {
12583 1491 auto &kd = it.second;
12584
3/6
✓ Branch 0 taken 1491 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1491 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1491 times.
✗ Branch 5 not taken.
1491 ranges[kd->get_cf()].push_back(ha_rocksdb::get_range(*kd, bufp));
12585 1491 bufp += 2 * Rdb_key_def::INDEX_NUMBER_SIZE;
12586 }
12587
12588 // get RocksDB table properties for these ranges
12589 466 rocksdb::TablePropertiesCollection props;
12590
2/2
✓ Branch 0 taken 505 times.
✓ Branch 1 taken 466 times.
971 for (const auto &it : ranges) {
12591 505 const auto old_size MY_ATTRIBUTE((__unused__)) = props.size();
12592 505 const auto status = rdb->GetPropertiesOfTablesInRange(
12593
1/2
✓ Branch 0 taken 505 times.
✗ Branch 1 not taken.
505 it.first, &it.second[0], it.second.size(), &props);
12594
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 505 times.
505 assert(props.size() >= old_size);
12595
2/4
✓ Branch 0 taken 505 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 505 times.
505 if (!status.ok()) {
12596 DBUG_RETURN(ha_rocksdb::rdb_error_to_mysql(
12597 status, "Could not access RocksDB properties"));
12598 }
12599
1/2
✓ Branch 0 taken 505 times.
✗ Branch 1 not taken.
505 }
12600
12601 466 int num_sst = 0;
12602
2/2
✓ Branch 0 taken 1116 times.
✓ Branch 1 taken 466 times.
1582 for (const auto &it : props) {
12603 1116 std::vector<Rdb_index_stats> sst_stats;
12604
1/2
✓ Branch 0 taken 1116 times.
✗ Branch 1 not taken.
1116 Rdb_tbl_prop_coll::read_stats_from_tbl_props(it.second, &sst_stats);
12605 /*
12606 sst_stats is a list of index statistics for indexes that have entries
12607 in the current SST file.
12608 */
12609
2/2
✓ Branch 0 taken 20501 times.
✓ Branch 1 taken 1116 times.
21617 for (const auto &it1 : sst_stats) {
12610 /*
12611 Only update statistics for indexes that belong to this SQL table.
12612
12613 The reason is: We are walking through all SST files that have
12614 entries from this table (and so can compute good statistics). For
12615 other SQL tables, it can be that we're only seeing a small fraction
12616 of table's entries (and so we can't update statistics based on that).
12617 */
12618
3/4
✓ Branch 0 taken 20501 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17373 times.
✓ Branch 3 taken 3128 times.
20501 if (stats->find(it1.m_gl_index_id) == stats->end()) {
12619 17373 continue;
12620 }
12621
12622
1/2
✓ Branch 0 taken 3128 times.
✗ Branch 1 not taken.
3128 auto it_index = to_recalc.find(it1.m_gl_index_id);
12623
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3128 times.
3128 assert(it_index != to_recalc.end());
12624
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3128 times.
3128 if (it_index == to_recalc.end()) {
12625 continue;
12626 }
12627
12628
2/4
✓ Branch 0 taken 3128 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3128 times.
✗ Branch 3 not taken.
6256 (*stats)[it1.m_gl_index_id].merge(
12629 3128 it1, true, it_index->second->max_storage_fmt_length());
12630 }
12631 1116 num_sst++;
12632 1116 }
12633
12634
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 DBUG_RETURN(HA_EXIT_SUCCESS);
12635 466 }
12636
12637 466 static int calculate_stats(
12638 const std::unordered_map<GL_INDEX_ID, std::shared_ptr<const Rdb_key_def>>
12639 &to_recalc,
12640 table_cardinality_scan_type scan_type,
12641 std::atomic<THD::killed_state> *killed) {
12642
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 DBUG_ENTER_FUNC();
12643
12644 466 std::unordered_map<GL_INDEX_ID, Rdb_index_stats> stats;
12645
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 int ret = read_stats_from_ssts(to_recalc, &stats);
12646
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 466 times.
466 if (ret != HA_EXIT_SUCCESS) {
12647 DBUG_RETURN(ret);
12648 }
12649
12650
2/2
✓ Branch 0 taken 442 times.
✓ Branch 1 taken 24 times.
466 if (scan_type != SCAN_TYPE_NONE) {
12651 442 std::unordered_map<GL_INDEX_ID, Rdb_index_stats> card_stats;
12652 442 uint64_t max_num_rows_scanned = rocksdb_table_stats_max_num_rows_scanned;
12653
1/2
✓ Branch 0 taken 442 times.
✗ Branch 1 not taken.
442 ret = calculate_cardinality_table_scan(to_recalc, &card_stats, scan_type,
12654 max_num_rows_scanned, killed);
12655
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 442 times.
442 if (ret != HA_EXIT_SUCCESS) {
12656 DBUG_RETURN(ret);
12657 }
12658
12659
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 393 times.
442 if (scan_type == SCAN_TYPE_FULL_TABLE) {
12660
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
49 reset_cardinality(&stats);
12661 }
12662
12663
1/2
✓ Branch 0 taken 442 times.
✗ Branch 1 not taken.
442 merge_stats(to_recalc, &stats, card_stats);
12664
3/4
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 393 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 49 times.
442 if (scan_type == SCAN_TYPE_FULL_TABLE && max_num_rows_scanned > 0) {
12665 adjust_cardinality(&stats, scan_type, max_num_rows_scanned);
12666 }
12667
1/2
✓ Branch 0 taken 442 times.
✗ Branch 1 not taken.
442 }
12668
12669 // set and persist new stats
12670
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 ddl_manager.set_stats(stats);
12671
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 ddl_manager.persist_stats(true);
12672
12673
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 DBUG_RETURN(HA_EXIT_SUCCESS);
12674 466 }
12675
12676 466 static int calculate_stats_for_table(
12677 const std::string &tbl_name, table_cardinality_scan_type scan_type,
12678 std::atomic<THD::killed_state> *killed = nullptr) {
12679
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 DBUG_ENTER_FUNC();
12680 466 std::unordered_map<GL_INDEX_ID, std::shared_ptr<const Rdb_key_def>> to_recalc;
12681 466 std::vector<GL_INDEX_ID> indexes;
12682
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 ddl_manager.find_indexes(tbl_name, &indexes);
12683
12684
2/2
✓ Branch 0 taken 1491 times.
✓ Branch 1 taken 466 times.
1957 for (const auto &index : indexes) {
12685
1/2
✓ Branch 0 taken 1491 times.
✗ Branch 1 not taken.
1491 std::shared_ptr<const Rdb_key_def> keydef = ddl_manager.safe_find(index);
12686
12687
1/2
✓ Branch 0 taken 1491 times.
✗ Branch 1 not taken.
1491 if (keydef) {
12688
3/6
✓ Branch 0 taken 1491 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1491 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1491 times.
✗ Branch 5 not taken.
1491 to_recalc.insert(std::make_pair(keydef->get_gl_index_id(), keydef));
12689 }
12690 1491 }
12691
12692
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 466 times.
466 if (to_recalc.empty()) {
12693 DBUG_RETURN(HA_EXIT_FAILURE);
12694 }
12695
12696
11/20
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 463 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✗ Branch 19 not taken.
466 DBUG_EXECUTE_IF("rocksdb_is_bg_thread_drop_table", {
12697 if (tbl_name == "test.t") {
12698 THD *thd = new THD();
12699 thd->thread_stack = reinterpret_cast<char *>(&thd);
12700 thd->store_globals();
12701
12702 static constexpr char act[] = "now signal ready_to_drop_table";
12703 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
12704
12705 thd->restore_globals();
12706 delete thd;
12707 }
12708 });
12709
12710
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 int err = calculate_stats(to_recalc, scan_type, killed);
12711
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 466 times.
466 if (err != HA_EXIT_SUCCESS) {
12712 DBUG_RETURN(err);
12713 }
12714
12715
11/20
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 463 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✗ Branch 19 not taken.
466 DBUG_EXECUTE_IF("rocksdb_is_bg_thread_drop_table", {
12716 if (tbl_name == "test.t") {
12717 THD *thd = new THD();
12718 thd->thread_stack = reinterpret_cast<char *>(&thd);
12719 thd->store_globals();
12720
12721 static constexpr char act[] = "now wait_for ready_to_save_table_stats";
12722 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
12723
12724 thd->restore_globals();
12725 delete thd;
12726 }
12727 });
12728
12729
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 417 times.
466 if (scan_type == SCAN_TYPE_FULL_TABLE) {
12730 // Save table stats including number of rows
12731 // and modified counter
12732
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
49 ddl_manager.set_table_stats(tbl_name);
12733 }
12734
12735
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 DBUG_RETURN(HA_EXIT_SUCCESS);
12736 466 }
12737
12738 /*
12739 @return
12740 HA_ADMIN_OK OK
12741 other HA_ADMIN error code
12742 */
12743 405 int ha_rocksdb::analyze(THD *const thd, HA_CHECK_OPT *const check_opt) {
12744
1/2
✓ Branch 0 taken 405 times.
✗ Branch 1 not taken.
405 DBUG_ENTER_FUNC();
12745
12746
1/2
✓ Branch 0 taken 405 times.
✗ Branch 1 not taken.
405 if (table) {
12747 405 table_cardinality_scan_type scan_type = rocksdb_table_stats_use_table_scan
12748
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 393 times.
405 ? SCAN_TYPE_FULL_TABLE
12749 : SCAN_TYPE_MEMTABLE_ONLY;
12750
12751
1/2
✓ Branch 0 taken 405 times.
✗ Branch 1 not taken.
405 if (calculate_stats_for_table(m_tbl_def->full_tablename(), scan_type,
12752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 405 times.
405 &(thd->killed)) != HA_EXIT_SUCCESS) {
12753 DBUG_RETURN(HA_ADMIN_FAILED);
12754 }
12755 }
12756
12757
1/2
✓ Branch 0 taken 405 times.
✗ Branch 1 not taken.
405 DBUG_RETURN(HA_ADMIN_OK);
12758 }
12759
12760 463014 int ha_rocksdb::adjust_handler_stats_sst_and_memtable(ha_statistics *ha_stats,
12761 Rdb_tbl_def *tbl_def) {
12762
1/2
✓ Branch 0 taken 463015 times.
✗ Branch 1 not taken.
463014 DBUG_ENTER_FUNC();
12763
12764 /*
12765 If any stats are negative due to bad cached stats, re-run analyze table
12766 and re-retrieve the stats.
12767 */
12768
2/2
✓ Branch 0 taken 463001 times.
✓ Branch 1 taken 14 times.
463015 if (static_cast<longlong>(ha_stats->data_file_length) < 0 ||
12769
2/2
✓ Branch 0 taken 462992 times.
✓ Branch 1 taken 9 times.
463001 static_cast<longlong>(ha_stats->index_file_length) < 0 ||
12770
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 462992 times.
462992 static_cast<longlong>(ha_stats->records) < 0) {
12771
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
23 if (calculate_stats_for_table(tbl_def->full_tablename(), SCAN_TYPE_NONE)) {
12772 DBUG_RETURN(HA_EXIT_FAILURE);
12773 }
12774
12775 24 rocksdb_get_stats(ha_stats, tbl_def);
12776 }
12777
12778 // if number of records is hardcoded, we do not want to force computation
12779 // of memtable cardinalities
12780
4/4
✓ Branch 0 taken 330129 times.
✓ Branch 1 taken 132887 times.
✓ Branch 2 taken 330128 times.
✓ Branch 3 taken 1 times.
463016 if (ha_stats->records == 0 || (rocksdb_force_compute_memtable_stats &&
12781
2/2
✓ Branch 0 taken 313264 times.
✓ Branch 1 taken 16864 times.
330128 rocksdb_debug_optimizer_n_rows == 0)) {
12782 // First, compute SST files stats
12783 uchar buf[Rdb_key_def::INDEX_NUMBER_SIZE * 2];
12784 446151 std::shared_ptr<Rdb_key_def> pk_def = tbl_def->get_pk_def();
12785
1/2
✓ Branch 0 taken 446150 times.
✗ Branch 1 not taken.
446151 auto r = ha_rocksdb::get_range(*pk_def, buf);
12786 446150 uint64_t sz = 0;
12787
12788 446150 rocksdb::DB::SizeApproximationFlags include_flags =
12789 rocksdb::DB::SizeApproximationFlags::INCLUDE_FILES;
12790
12791 // recompute SST files stats only if records count is 0
12792
2/2
✓ Branch 0 taken 132886 times.
✓ Branch 1 taken 313264 times.
446150 if (ha_stats->records == 0) {
12793
1/2
✓ Branch 0 taken 132884 times.
✗ Branch 1 not taken.
132886 rdb->GetApproximateSizes(pk_def->get_cf(), &r, 1, &sz, include_flags);
12794 132886 ha_stats->records += sz / ROCKSDB_ASSUMED_KEY_VALUE_DISK_SIZE;
12795 132886 ha_stats->data_file_length += sz;
12796 }
12797
12798 // Second, compute memtable stats. This call is expensive, so cache
12799 // values computed for some time.
12800 446150 uint64_t cachetime = rocksdb_force_compute_memtable_stats_cachetime;
12801
2/2
✓ Branch 0 taken 32192 times.
✓ Branch 1 taken 413958 times.
446150 uint64_t time = (cachetime == 0) ? 0 : my_micro_time();
12802
4/4
✓ Branch 0 taken 32192 times.
✓ Branch 1 taken 413958 times.
✓ Branch 2 taken 4894 times.
✓ Branch 3 taken 27298 times.
446150 if (cachetime == 0 || time > tbl_def->m_mtcache_last_update + cachetime) {
12803 uint64_t memtableCount;
12804 uint64_t memtableSize;
12805
12806 // the stats below are calculated from skiplist wich is a probablistic
12807 // data structure, so the results vary between test runs
12808 // it also can return 0 for quite a large tables which means that
12809 // cardinality for memtable only indxes will be reported as 0
12810
12811
1/2
✓ Branch 0 taken 418851 times.
✗ Branch 1 not taken.
418852 rdb->GetApproximateMemTableStats(pk_def->get_cf(), r, &memtableCount,
12812 &memtableSize);
12813
12814 // Atomically update all of these fields at the same time
12815
2/2
✓ Branch 0 taken 4894 times.
✓ Branch 1 taken 413957 times.
418851 if (cachetime > 0) {
12816
1/2
✓ Branch 0 taken 4894 times.
✗ Branch 1 not taken.
9788 if (tbl_def->m_mtcache_lock.fetch_add(1, std::memory_order_acquire) ==
12817 0) {
12818 4894 tbl_def->m_mtcache_count = memtableCount;
12819 4894 tbl_def->m_mtcache_size = memtableSize;
12820 4894 tbl_def->m_mtcache_last_update = time;
12821 }
12822 4894 tbl_def->m_mtcache_lock.fetch_sub(1, std::memory_order_release);
12823 }
12824
12825 418851 ha_stats->records += memtableCount;
12826 418851 ha_stats->data_file_length += memtableSize;
12827 418851 } else {
12828 // Cached data is still valid, so use it instead
12829 27298 ha_stats->records += tbl_def->m_mtcache_count;
12830 27298 ha_stats->data_file_length += tbl_def->m_mtcache_size;
12831 }
12832 446149 }
12833
12834
1/2
✓ Branch 0 taken 463015 times.
✗ Branch 1 not taken.
463015 DBUG_RETURN(HA_EXIT_SUCCESS);
12835 }
12836
12837 6625450 void ha_rocksdb::get_auto_increment(ulonglong off, ulonglong inc,
12838 ulonglong nb_desired_values,
12839 ulonglong *const first_value,
12840 ulonglong *const nb_reserved_values) {
12841 /*
12842 MySQL has a somewhat complicated way of handling the auto-increment value.
12843 The first time get_auto_increment is called for a statement,
12844 nb_desired_values is the estimate for how many values will be needed. The
12845 engine can then reserve some values, and those will be automatically used
12846 by MySQL, until a hard-coded value shows up in the insert statement, after
12847 which MySQL again calls this function to reset its starting value.
12848 *
12849 For simplicity we will just ignore nb_desired_values - we aren't going to
12850 reserve any extra values for a multi-insert statement. Each row will
12851 simply acquire the next value as needed and we will always tell MySQL that
12852 we only reserved 1 value. Since we are using an atomic value for
12853 m_auto_incr_val this should be safe - if we had to grab a mutex, doing
12854 an actual reserve of some values might be a better solution.
12855 */
12856
3/6
✓ Branch 0 taken 6687311 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6700487 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6730244 times.
✗ Branch 5 not taken.
6625450 DEBUG_SYNC(ha_thd(), "rocksdb.autoinc_vars");
12857
12858
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 6705605 times.
6705623 if (off > inc) {
12859 18 off = 1;
12860 }
12861
12862 Field *field;
12863 ulonglong new_val, max_val;
12864 6705623 field = table->key_info[table->s->next_number_index].key_part[0].field;
12865
1/2
✓ Branch 0 taken 6678766 times.
✗ Branch 1 not taken.
6705623 max_val = rdb_get_int_col_max_value(field);
12866
12867 // Local variable reference to simplify code below
12868 6678766 auto &auto_incr = m_tbl_def->m_auto_incr_val;
12869
12870
2/2
✓ Branch 0 taken 3745683 times.
✓ Branch 1 taken 2933083 times.
6678766 if (inc == 1) {
12871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3745683 times.
3745683 assert(off == 1);
12872 // Optimization for the standard case where we are always simply
12873 // incrementing from the last position
12874
12875 // Use CAS operation in a loop to make sure automically get the next auto
12876 // increment value while ensuring that we don't wrap around to a negative
12877 // number.
12878 //
12879 // We set auto_incr to the min of max_val and new_val + 1. This means that
12880 // if we're at the maximum, we should be returning the same value for
12881 // multiple rows, resulting in duplicate key errors (as expected).
12882 //
12883 // If we return values greater than the max, the SQL layer will "truncate"
12884 // the value anyway, but it means that we store invalid values into
12885 // auto_incr that will be visible in SHOW CREATE TABLE.
12886 3745683 new_val = auto_incr;
12887
2/2
✓ Branch 0 taken 3746059 times.
✓ Branch 1 taken 3 times.
3746114 while (new_val != std::numeric_limits<ulonglong>::max()) {
12888 3746026 if (auto_incr.compare_exchange_weak(new_val,
12889
2/2
✓ Branch 0 taken 3745891 times.
✓ Branch 1 taken 645 times.
7492595 std::min(new_val + 1, max_val))) {
12890 3745891 break;
12891 }
12892 }
12893 } else {
12894 // The next value can be more complicated if either 'inc' or 'off' is not 1
12895 2933083 ulonglong last_val = auto_incr;
12896
12897
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2924946 times.
2924952 if (last_val > max_val) {
12898 6 new_val = std::numeric_limits<ulonglong>::max();
12899 } else {
12900 // Loop until we can correctly update the atomic value
12901 do {
12902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3090472 times.
3090472 assert(last_val > 0);
12903 // Calculate the next value in the auto increment series: offset
12904 // + N * increment where N is 0, 1, 2, ...
12905 //
12906 // For further information please visit:
12907 // http://dev.mysql.com/doc/refman/5.7/en/replication-options-master.html
12908 //
12909 // The following is confusing so here is an explanation:
12910 // To get the next number in the sequence above you subtract out the
12911 // offset, calculate the next sequence (N * increment) and then add the
12912 // offset back in.
12913 //
12914 // The additions are rearranged to avoid overflow. The following is
12915 // equivalent to (last_val - 1 + inc - off) / inc. This uses the fact
12916 // that (a+b)/c = a/c + b/c + (a%c + b%c)/c. To show why:
12917 //
12918 // (a+b)/c
12919 // = (a - a%c + a%c + b - b%c + b%c) / c
12920 // = (a - a%c) / c + (b - b%c) / c + (a%c + b%c) / c
12921 // = a/c + b/c + (a%c + b%c) / c
12922 //
12923 // Now, substitute a = last_val - 1, b = inc - off, c = inc to get the
12924 // following statement.
12925 3090472 ulonglong n =
12926 3090472 (last_val - 1) / inc + ((last_val - 1) % inc + inc - off) / inc;
12927
12928 // Check if n * inc + off will overflow. This can only happen if we have
12929 // an UNSIGNED BIGINT field.
12930
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3059975 times.
3090472 if (n > (std::numeric_limits<ulonglong>::max() - off) / inc) {
12931
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 assert(max_val == std::numeric_limits<ulonglong>::max());
12932 // The 'last_val' value is already equal to or larger than the largest
12933 // value in the sequence. Continuing would wrap around (technically
12934 // the behavior would be undefined). What should we do?
12935 // We could:
12936 // 1) set the new value to the last possible number in our sequence
12937 // as described above. The problem with this is that this
12938 // number could be smaller than a value in an existing row.
12939 // 2) set the new value to the largest possible number. This number
12940 // may not be in our sequence, but it is guaranteed to be equal
12941 // to or larger than any other value already inserted.
12942 //
12943 // For now I'm going to take option 2.
12944 //
12945 // Returning ULLONG_MAX from get_auto_increment will cause the SQL
12946 // layer to fail with ER_AUTOINC_READ_FAILED. This means that due to
12947 // the SE API for get_auto_increment, inserts will fail with
12948 // ER_AUTOINC_READ_FAILED if the column is UNSIGNED BIGINT, but
12949 // inserts will fail with ER_DUP_ENTRY for other types (or no failure
12950 // if the column is in a non-unique SK).
12951 12 new_val = std::numeric_limits<ulonglong>::max();
12952 12 auto_incr = new_val; // Store the largest value into auto_incr
12953 13084 break;
12954 }
12955
12956 3059975 new_val = n * inc + off;
12957
12958 // Attempt to store the new value (plus 1 since m_auto_incr_val contains
12959 // the next available value) into the atomic value. If the current
12960 // value no longer matches what we have in 'last_val' this will fail and
12961 // we will repeat the loop (`last_val` will automatically get updated
12962 // with the current value).
12963 //
12964 // See above explanation for inc == 1 for why we use std::min.
12965 3056946 } while (!auto_incr.compare_exchange_weak(
12966
2/2
✓ Branch 0 taken 165526 times.
✓ Branch 1 taken 2986979 times.
6212480 last_val, std::min(new_val + 1, max_val)));
12967 }
12968 }
12969
12970 6745963 *first_value = new_val;
12971 6745963 *nb_reserved_values = 1;
12972 6745963 }
12973
12974 #ifndef NDEBUG
12975
12976 /* Debugger help function */
12977 static char dbug_item_print_buf[512];
12978
12979 const char *dbug_print_item(const THD *thd, Item *const item) {
12980 char *const buf = dbug_item_print_buf;
12981 String str(buf, sizeof(dbug_item_print_buf), &my_charset_bin);
12982 str.length(0);
12983 if (!item) return "(Item*)nullptr";
12984 item->print(thd, &str, QT_ORDINARY);
12985 if (str.c_ptr() == buf) {
12986 return buf;
12987 } else {
12988 return "Couldn't fit into buffer";
12989 }
12990 }
12991
12992 #endif /*NDEBUG*/
12993
12994 /**
12995 SQL layer calls this function to push an index condition.
12996
12997 @details
12998 The condition is for index keyno (only one condition can be pushed at a
12999 time).
13000 The caller guarantees that condition refers only to index fields; besides
13001 that, fields must have
13002
13003 $field->part_of_key.set_bit(keyno)
13004
13005 which means that
13006
13007 (handler->index_flags(keyno, $keypart, 0) & HA_KEYREAD_ONLY) == 1
13008
13009 which means that field value can be restored from the index tuple.
13010
13011 @return
13012 Part of condition we couldn't check (always nullptr).
13013 */
13014
13015 1675 class Item *ha_rocksdb::idx_cond_push(uint keyno, class Item *const idx_cond) {
13016
1/2
✓ Branch 0 taken 1675 times.
✗ Branch 1 not taken.
1675 DBUG_ENTER_FUNC();
13017
13018
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1675 times.
1675 assert(keyno != MAX_KEY);
13019
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1675 times.
1675 assert(idx_cond != nullptr);
13020
13021 1675 pushed_idx_cond = idx_cond;
13022 1675 pushed_idx_cond_keyno = keyno;
13023 1675 in_range_check_pushed_down = true;
13024
13025 /* We will check the whole condition */
13026
1/2
✓ Branch 0 taken 1675 times.
✗ Branch 1 not taken.
1675 DBUG_RETURN(nullptr);
13027 }
13028
13029 /*
13030 @brief
13031 Check the index condition.
13032
13033 @detail
13034 Check the index condition. (The caller has unpacked all needed index
13035 columns into table->record[0])
13036
13037 @return
13038 ICP_NO_MATCH - Condition not satisfied (caller should continue
13039 scanning)
13040 OUT_OF_RANGE - We've left the range we're scanning (caller should
13041 stop scanning and return HA_ERR_END_OF_FILE)
13042
13043 ICP_MATCH - Condition is satisfied (caller should fetch the record
13044 and return it)
13045 */
13046
13047 46503 enum icp_result ha_rocksdb::check_index_cond() const {
13048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46503 times.
46503 assert(pushed_idx_cond);
13049
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46503 times.
46503 assert(pushed_idx_cond_keyno != MAX_KEY);
13050
13051
6/6
✓ Branch 0 taken 19587 times.
✓ Branch 1 taken 26916 times.
✓ Branch 2 taken 365 times.
✓ Branch 3 taken 19222 times.
✓ Branch 4 taken 365 times.
✓ Branch 5 taken 46138 times.
46503 if (end_range && compare_key_icp(end_range) > 0) {
13052 /* caller should return HA_ERR_END_OF_FILE already */
13053 365 return ICP_OUT_OF_RANGE;
13054 }
13055
13056
2/2
✓ Branch 0 taken 45919 times.
✓ Branch 1 taken 219 times.
46138 return pushed_idx_cond->val_int() ? ICP_MATCH : ICP_NO_MATCH;
13057 }
13058
13059 /** Operations for altering a table that RocksDB does not care about */
13060 static const Alter_inplace_info::HA_ALTER_FLAGS ROCKSDB_INPLACE_IGNORE =
13061 Alter_inplace_info::ALTER_COLUMN_DEFAULT |
13062 Alter_inplace_info::ALTER_COLUMN_COLUMN_FORMAT |
13063 Alter_inplace_info::ALTER_COLUMN_STORAGE_TYPE |
13064 Alter_inplace_info::ALTER_RENAME | Alter_inplace_info::CHANGE_INDEX_OPTION |
13065 Alter_inplace_info::ADD_CHECK_CONSTRAINT |
13066 Alter_inplace_info::DROP_CHECK_CONSTRAINT |
13067 Alter_inplace_info::SUSPEND_CHECK_CONSTRAINT;
13068
13069 /*
13070 Checks if instant alter is supported for a given operation.
13071 */
13072 2263 ha_rocksdb::Instant_Type ha_rocksdb::rocksdb_support_instant(
13073 my_core::Alter_inplace_info *const ha_alter_info MY_ATTRIBUTE((unused)),
13074 const TABLE *old_table MY_ATTRIBUTE((unused)),
13075 const TABLE *altered_table MY_ATTRIBUTE((unused))) const {
13076
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2263 times.
2263 if (rocksdb_instant_ddl) {
13077 return Instant_Type::INSTANT_IMPOSSIBLE;
13078 }
13079
13080
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 2197 times.
2263 if (!(ha_alter_info->handler_flags & ~ROCKSDB_INPLACE_IGNORE)) {
13081 /* after adding support, return (Instant_Type::INSTANT_NO_CHANGE) */
13082 66 return (Instant_Type::INSTANT_IMPOSSIBLE);
13083 }
13084
13085 2197 Alter_inplace_info::HA_ALTER_FLAGS alter_inplace_flags =
13086 2197 ha_alter_info->handler_flags & ~ROCKSDB_INPLACE_IGNORE;
13087
13088 /* If it's only adding and(or) dropping virtual columns */
13089
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 2164 times.
2197 if (!(alter_inplace_flags & ~(Alter_inplace_info::ADD_VIRTUAL_COLUMN |
13090 Alter_inplace_info::DROP_VIRTUAL_COLUMN))) {
13091 /* after enable, return (Instant_Type::INSTANT_VIRTUAL_ONLY); */
13092 33 return (Instant_Type::INSTANT_IMPOSSIBLE);
13093 }
13094
13095 /* If it's an ADD COLUMN without changing existing column orders */
13096
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 2037 times.
2164 if (alter_inplace_flags == Alter_inplace_info::ADD_STORED_BASE_COLUMN) {
13097 /* after add col instant support, return Instant_Type::INSTANT_ADD_COLUMN
13098 * */
13099 127 return (Instant_Type::INSTANT_IMPOSSIBLE);
13100 }
13101
13102 // by default, impossible to do instant ddl
13103 2037 return (Instant_Type::INSTANT_IMPOSSIBLE);
13104 }
13105
13106 /*
13107 Checks if inplace alter is supported for a given operation.
13108 */
13109 2269 my_core::enum_alter_inplace_result ha_rocksdb::check_if_supported_inplace_alter(
13110 TABLE *altered_table, my_core::Alter_inplace_info *ha_alter_info) {
13111
1/2
✓ Branch 0 taken 2269 times.
✗ Branch 1 not taken.
2269 DBUG_ENTER_FUNC();
13112
13113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2269 times.
2269 assert(ha_alter_info != nullptr);
13114
13115 /* No need for a table rebuild when changing only index metadata */
13116
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2263 times.
2269 if (ha_alter_info->handler_flags == Alter_inplace_info::RENAME_INDEX &&
13117
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 ha_alter_info->alter_info->flags == Alter_info::ALTER_INDEX_VISIBILITY &&
13118
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 ha_alter_info->create_info->used_fields == 0) {
13119
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_RETURN(my_core::HA_ALTER_INPLACE_EXCLUSIVE_LOCK);
13120 }
13121
13122 /* check instant ddl type */
13123 Instant_Type instant_type =
13124
1/2
✓ Branch 0 taken 2263 times.
✗ Branch 1 not taken.
2263 rocksdb_support_instant(ha_alter_info, this->table, altered_table);
13125
13126 /* by default, impossible to do intant ddl */
13127 2263 ha_alter_info->handler_trivial_ctx =
13128 static_cast<uint8>(Instant_Type::INSTANT_IMPOSSIBLE);
13129
13130
1/4
✓ Branch 0 taken 2263 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2263 switch (instant_type) {
13131 2263 case Instant_Type::INSTANT_IMPOSSIBLE:
13132 2263 break;
13133 case Instant_Type::INSTANT_ADD_COLUMN:
13134 if (ha_alter_info->alter_info->requested_algorithm ==
13135 Alter_info::ALTER_TABLE_ALGORITHM_INPLACE) {
13136 /* Still fall back to INPLACE since the behaviour is different */
13137 break;
13138 } else if (ha_alter_info->error_if_not_empty) {
13139 /* In this case, it can't be instant because the table
13140 may not be empty. Have to fall back to INPLACE */
13141 break;
13142 }
13143 [[fallthrough]];
13144 case Instant_Type::INSTANT_NO_CHANGE:
13145 case Instant_Type::INSTANT_VIRTUAL_ONLY:
13146 ha_alter_info->handler_trivial_ctx = static_cast<uint8>(instant_type);
13147 DBUG_RETURN(HA_ALTER_INPLACE_INSTANT);
13148 }
13149
13150
2/2
✓ Branch 0 taken 1293 times.
✓ Branch 1 taken 970 times.
2263 if (ha_alter_info->handler_flags &
13151
2/2
✓ Branch 0 taken 2254 times.
✓ Branch 1 taken 9 times.
2263 ~(my_core::Alter_inplace_info::DROP_INDEX |
13152 my_core::Alter_inplace_info::DROP_UNIQUE_INDEX |
13153 my_core::Alter_inplace_info::ADD_INDEX |
13154 my_core::Alter_inplace_info::ADD_UNIQUE_INDEX |
13155 my_core::Alter_inplace_info::CHANGE_CREATE_OPTION |
13156 my_core::Alter_inplace_info::DROP_PARTITION |
13157 (rocksdb_alter_column_default_inplace
13158 ? my_core::Alter_inplace_info::ALTER_COLUMN_DEFAULT
13159 : 0))) {
13160
1/2
✓ Branch 0 taken 1293 times.
✗ Branch 1 not taken.
1293 DBUG_RETURN(my_core::HA_ALTER_INPLACE_NOT_SUPPORTED);
13161 }
13162
13163 /* We don't support unique keys on table w/ no primary keys */
13164 1940 if ((ha_alter_info->handler_flags &
13165
4/4
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 919 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 955 times.
1021 my_core::Alter_inplace_info::ADD_UNIQUE_INDEX) &&
13166
3/4
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 36 times.
51 has_hidden_pk(altered_table)) {
13167
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 DBUG_RETURN(my_core::HA_ALTER_INPLACE_NOT_SUPPORTED);
13168 }
13169
13170 /* We only support changing auto_increment for table options. */
13171
2/2
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 769 times.
955 if ((ha_alter_info->handler_flags &
13172 186 my_core::Alter_inplace_info::CHANGE_CREATE_OPTION) &&
13173
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 90 times.
186 !(ha_alter_info->create_info->used_fields & HA_CREATE_USED_AUTO)) {
13174
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 DBUG_RETURN(my_core::HA_ALTER_INPLACE_NOT_SUPPORTED);
13175 }
13176
13177
1/2
✓ Branch 0 taken 859 times.
✗ Branch 1 not taken.
859 DBUG_RETURN(my_core::HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE);
13178 }
13179
13180 /**
13181 Allows the storage engine to update internal structures with concurrent
13182 writes blocked. If check_if_supported_inplace_alter() returns
13183 HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE or
13184 HA_ALTER_INPLACE_SHARED_AFTER_PREPARE, this function is called with
13185 exclusive lock otherwise the same level of locking as for
13186 inplace_alter_table() will be used.
13187
13188 @note Storage engines are responsible for reporting any errors by
13189 calling my_error()/print_error()
13190
13191 @note If this function reports error, commit_inplace_alter_table()
13192 will be called with commit= false.
13193
13194 @note For partitioning, failing to prepare one partition, means that
13195 commit_inplace_alter_table() will be called to roll back changes for
13196 all partitions. This means that commit_inplace_alter_table() might be
13197 called without prepare_inplace_alter_table() having been called first
13198 for a given partition.
13199
13200 @param altered_table TABLE object for new version of table.
13201 @param ha_alter_info Structure describing changes to be done
13202 by ALTER TABLE and holding data used
13203 during in-place alter.
13204
13205 @retval true Error
13206 @retval false Success
13207 */
13208 1144 bool ha_rocksdb::prepare_inplace_alter_table(
13209 TABLE *altered_table, my_core::Alter_inplace_info *ha_alter_info,
13210 const dd::Table *old_table_def MY_ATTRIBUTE((__unused__)),
13211 dd::Table *new_table_def MY_ATTRIBUTE((__unused__))) {
13212
1/2
✓ Branch 0 taken 1144 times.
✗ Branch 1 not taken.
1144 DBUG_ENTER_FUNC();
13213
13214
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1144 times.
1144 assert(altered_table != nullptr);
13215
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1144 times.
1144 assert(ha_alter_info != nullptr);
13216
13217 1144 Rdb_tbl_def *new_tdef = nullptr;
13218 1144 std::shared_ptr<Rdb_key_def> *old_key_descr = nullptr;
13219 1144 std::shared_ptr<Rdb_key_def> *new_key_descr = nullptr;
13220 1144 uint old_n_keys = m_tbl_def->m_key_count;
13221 1144 uint new_n_keys = altered_table->s->keys;
13222 1144 std::unordered_set<std::shared_ptr<Rdb_key_def>> added_indexes;
13223 1144 std::unordered_set<GL_INDEX_ID> dropped_index_ids;
13224 1144 uint n_dropped_keys = 0;
13225 1144 uint n_added_keys = 0;
13226 1144 ulonglong max_auto_incr = 0;
13227
13228
2/2
✓ Branch 0 taken 601 times.
✓ Branch 1 taken 543 times.
1144 if (ha_alter_info->handler_flags &
13229 (my_core::Alter_inplace_info::DROP_INDEX |
13230 my_core::Alter_inplace_info::DROP_UNIQUE_INDEX |
13231 my_core::Alter_inplace_info::ADD_INDEX |
13232 my_core::Alter_inplace_info::ADD_UNIQUE_INDEX)) {
13233
3/4
✓ Branch 0 taken 601 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
✓ Branch 3 taken 409 times.
601 if (has_hidden_pk(altered_table)) {
13234 192 new_n_keys += 1;
13235 }
13236
13237 601 const TABLE *const old_table = table;
13238 601 old_key_descr = m_tbl_def->m_key_descr_arr;
13239
4/6
✓ Branch 0 taken 601 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 601 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1435 times.
✓ Branch 5 taken 601 times.
2036 new_key_descr = new std::shared_ptr<Rdb_key_def>[new_n_keys];
13240
13241
2/4
✓ Branch 0 taken 601 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 601 times.
✗ Branch 3 not taken.
601 new_tdef = new Rdb_tbl_def(m_tbl_def->full_tablename());
13242 601 new_tdef->m_key_descr_arr = new_key_descr;
13243 601 new_tdef->m_key_count = new_n_keys;
13244 601 new_tdef->m_pk_index = altered_table->s->primary_key;
13245 601 new_tdef->m_auto_incr_val =
13246 601 m_tbl_def->m_auto_incr_val.load(std::memory_order_relaxed);
13247 601 new_tdef->m_hidden_pk_val =
13248 601 m_tbl_def->m_hidden_pk_val.load(std::memory_order_relaxed);
13249
13250
4/6
✓ Branch 0 taken 601 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 601 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 589 times.
601 if (create_key_defs(altered_table, new_tdef, "" /*actual_user_table_name*/,
13251 601 table, m_tbl_def)) {
13252 /* Delete the new key descriptors */
13253
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
48 delete[] new_key_descr;
13254
13255 /*
13256 Explicitly mark as nullptr so we don't accidentally remove entries
13257 from data dictionary on cleanup (or cause double delete[]).
13258 */
13259 12 new_tdef->m_key_descr_arr = nullptr;
13260
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 delete new_tdef;
13261
13262
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 my_error(ER_KEY_CREATE_DURING_ALTER, MYF(0));
13263
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 DBUG_RETURN(HA_EXIT_FAILURE);
13264 }
13265
13266 uint i;
13267 uint j;
13268
13269 /* Determine which(if any) key definition(s) need to be dropped */
13270
2/2
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 589 times.
771 for (i = 0; i < ha_alter_info->index_drop_count; i++) {
13271 182 const KEY *const dropped_key = ha_alter_info->index_drop_buffer[i];
13272
1/2
✓ Branch 0 taken 358 times.
✗ Branch 1 not taken.
358 for (j = 0; j < old_n_keys; j++) {
13273 const KEY *const old_key =
13274 358 &old_table->key_info[old_key_descr[j]->get_keyno()];
13275
13276
3/4
✓ Branch 0 taken 358 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 182 times.
✓ Branch 3 taken 176 times.
358 if (!compare_keys(old_key, dropped_key)) {
13277
2/4
✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 182 times.
✗ Branch 3 not taken.
182 dropped_index_ids.insert(old_key_descr[j]->get_gl_index_id());
13278 182 break;
13279 }
13280 }
13281 }
13282
13283 /* Determine which(if any) key definitions(s) need to be added */
13284 589 int identical_indexes_found = 0;
13285
2/2
✓ Branch 0 taken 466 times.
✓ Branch 1 taken 589 times.
1055 for (i = 0; i < ha_alter_info->index_add_count; i++) {
13286 466 const KEY *const added_key =
13287 466 &ha_alter_info->key_info_buffer[ha_alter_info->index_add_buffer[i]];
13288
1/2
✓ Branch 0 taken 1013 times.
✗ Branch 1 not taken.
1013 for (j = 0; j < new_n_keys; j++) {
13289 const KEY *const new_key =
13290 1013 &altered_table->key_info[new_key_descr[j]->get_keyno()];
13291
3/4
✓ Branch 0 taken 1013 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 466 times.
✓ Branch 3 taken 547 times.
1013 if (!compare_keys(new_key, added_key)) {
13292 /*
13293 Check for cases where an 'identical' index is being dropped and
13294 re-added in a single ALTER statement. Turn this into a no-op as the
13295 index has not changed.
13296
13297 E.G. Unique index -> non-unique index requires no change
13298
13299 Note that cases where the index name remains the same but the
13300 key-parts are changed is already handled in create_inplace_key_defs.
13301 In these cases the index needs to be rebuilt.
13302 */
13303
3/6
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 466 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 466 times.
466 if (dropped_index_ids.count(new_key_descr[j]->get_gl_index_id())) {
13304 dropped_index_ids.erase(new_key_descr[j]->get_gl_index_id());
13305 identical_indexes_found++;
13306 } else {
13307
1/2
✓ Branch 0 taken 466 times.
✗ Branch 1 not taken.
466 added_indexes.insert(new_key_descr[j]);
13308 }
13309
13310 466 break;
13311 }
13312 }
13313 }
13314
13315 589 n_dropped_keys = ha_alter_info->index_drop_count - identical_indexes_found;
13316 589 n_added_keys = ha_alter_info->index_add_count - identical_indexes_found;
13317
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 589 times.
589 assert(dropped_index_ids.size() == n_dropped_keys);
13318
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 589 times.
589 assert(added_indexes.size() == n_added_keys);
13319
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 589 times.
589 assert(new_n_keys == (old_n_keys - n_dropped_keys + n_added_keys));
13320 }
13321
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 1042 times.
1132 if (ha_alter_info->handler_flags &
13322 my_core::Alter_inplace_info::CHANGE_CREATE_OPTION) {
13323
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 24 times.
90 if (!new_tdef) {
13324 66 new_tdef = m_tbl_def;
13325 }
13326
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 3 times.
90 if (table->found_next_number_field) {
13327
1/2
✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
87 max_auto_incr = load_auto_incr_value_from_index();
13328 }
13329 }
13330
13331
4/8
✓ Branch 0 taken 1132 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1132 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1132 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1132 times.
✗ Branch 7 not taken.
3396 ha_alter_info->handler_ctx = new (*THR_MALLOC)
13332 Rdb_inplace_alter_ctx(new_tdef, old_key_descr, new_key_descr, old_n_keys,
13333 new_n_keys, added_indexes, dropped_index_ids,
13334
1/2
✓ Branch 0 taken 1132 times.
✗ Branch 1 not taken.
2264 n_added_keys, n_dropped_keys, max_auto_incr);
13335
1/2
✓ Branch 0 taken 1132 times.
✗ Branch 1 not taken.
1132 DBUG_RETURN(HA_EXIT_SUCCESS);
13336 1144 }
13337
13338 /**
13339 Alter the table structure in-place with operations specified using
13340 HA_ALTER_FLAGS and Alter_inplace_info. The level of concurrency allowed
13341 during this operation depends on the return value from
13342 check_if_supported_inplace_alter().
13343
13344 @note Storage engines are responsible for reporting any errors by
13345 calling my_error()/print_error()
13346
13347 @note If this function reports error, commit_inplace_alter_table()
13348 will be called with commit= false.
13349
13350 @param altered_table TABLE object for new version of table.
13351 @param ha_alter_info Structure describing changes to be done
13352 by ALTER TABLE and holding data used
13353 during in-place alter.
13354
13355 @retval true Error
13356 @retval false Success
13357 */
13358 1129 bool ha_rocksdb::inplace_alter_table(
13359 TABLE *altered_table, my_core::Alter_inplace_info *ha_alter_info,
13360 const dd::Table *old_table_def MY_ATTRIBUTE((__unused__)),
13361 dd::Table *new_table_def MY_ATTRIBUTE((__unused__))) {
13362
1/2
✓ Branch 0 taken 1129 times.
✗ Branch 1 not taken.
1129 DBUG_ENTER_FUNC();
13363
13364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1129 times.
1129 assert(altered_table != nullptr);
13365
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1129 times.
1129 assert(ha_alter_info != nullptr);
13366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1129 times.
1129 assert(ha_alter_info->handler_ctx != nullptr);
13367
13368 1129 bool res = HA_EXIT_SUCCESS;
13369 1129 Rdb_inplace_alter_ctx *const ctx =
13370 static_cast<Rdb_inplace_alter_ctx *>(ha_alter_info->handler_ctx);
13371
13372
2/2
✓ Branch 0 taken 686 times.
✓ Branch 1 taken 443 times.
1129 if (!(ha_alter_info->handler_flags &
13373 (my_core::Alter_inplace_info::ADD_INDEX |
13374 my_core::Alter_inplace_info::ADD_UNIQUE_INDEX))) {
13375
1/2
✓ Branch 0 taken 686 times.
✗ Branch 1 not taken.
686 DBUG_RETURN(res);
13376 }
13377
13378 /*
13379 Buffers need to be set up again to account for new, possibly longer
13380 secondary keys.
13381 */
13382
1/2
✓ Branch 0 taken 443 times.
✗ Branch 1 not taken.
443 free_key_buffers();
13383
13384
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 443 times.
443 assert(ctx != nullptr);
13385
13386 /*
13387 If adding unique index, allocate special buffers for duplicate checking.
13388 */
13389 int err;
13390
2/4
✓ Branch 0 taken 443 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 443 times.
443 if ((err = alloc_key_buffers(altered_table, ctx->m_new_tdef))) {
13391 my_error(ER_OUT_OF_RESOURCES, MYF(0));
13392 res = HA_EXIT_FAILURE;
13393 goto end;
13394 }
13395
13396 /* Populate all new secondary keys by scanning the primary key. */
13397
3/4
✓ Branch 0 taken 440 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 416 times.
443 if ((err = inplace_populate_sk(altered_table, ctx->m_added_indexes))) {
13398
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 my_error(ER_SK_POPULATE_DURING_ALTER, MYF(0));
13399 24 res = HA_EXIT_FAILURE;
13400 24 goto end;
13401 }
13402
13403
4/6
✓ Branch 0 taken 416 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 415 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
416 DBUG_EXECUTE_IF("myrocks_simulate_index_create_rollback", {
13404 dbug_create_err_inplace_alter();
13405 res = HA_EXIT_FAILURE;
13406 };);
13407
13408 415 end:
13409 // During inplace_populate_sk, we may perform duplicate key checking which
13410 // involves calling unpack_record. However, blobs end up being unpacked
13411 // using the buffer in altered_table->file, instead of the current handler
13412 // object. This handler does not get cleaned up as it was never
13413 // opened, so we end up leaking that buffer. To fix, we call free_key_buffers
13414 // here.
13415 //
13416 // In the partitioned case, the altered_table->file is not only unopened, but
13417 // also unintialized, but we only unpack on duplicate key errors, and the
13418 // error is not possible on partitioned tables because indexes must include
13419 // the partitioning key which must include the primary key.
13420 //
13421 // A better solution would be to pass in the blob buffer from the correct
13422 // handler explicitly into the unpack functions, so that
13423 // Rdb_key_def::unpack_record does not need to derive it from the TABLE
13424 // object, since the Rdb_key_def class are generally unaware of handler
13425 // classes anyway.
13426
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 425 times.
440 if (err == ER_DUP_ENTRY) {
13427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 assert(ha_alter_info->group_commit_ctx == nullptr);
13428
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 reinterpret_cast<ha_rocksdb *>(altered_table->file)->free_key_buffers();
13429 }
13430
13431 // Try to reallocate key buffers from the old schema.
13432 //
13433 // A better fix may to save the original buffers to avoid needing to
13434 // reallocate here.
13435
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 415 times.
440 if (res == HA_EXIT_FAILURE) {
13436
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 free_key_buffers();
13437
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 err = alloc_key_buffers(table, m_tbl_def);
13438 }
13439
13440
1/2
✓ Branch 0 taken 440 times.
✗ Branch 1 not taken.
440 DBUG_RETURN(res);
13441 }
13442
13443 20898676 int ha_rocksdb::fill_virtual_columns() {
13444 /* Specify the columns the server should evaluate */
13445 20898676 MY_BITMAP column_map;
13446 20898676 bool bitmap_inited = false;
13447 my_bitmap_map col_map_storage[bitmap_buffer_size(1023)];
13448
2/2
✓ Branch 0 taken 59583251 times.
✓ Branch 1 taken 20898676 times.
80481927 for (uint i = 0; i < table->s->fields; i++) {
13449 59583251 auto &field = table->field[i];
13450
2/2
✓ Branch 0 taken 40410 times.
✓ Branch 1 taken 59542841 times.
59583251 if (field->is_virtual_gcol()) {
13451
2/2
✓ Branch 0 taken 19560 times.
✓ Branch 1 taken 20850 times.
40410 if (!bitmap_inited) {
13452
1/2
✓ Branch 0 taken 19560 times.
✗ Branch 1 not taken.
19560 bitmap_init(&column_map, col_map_storage, 1023);
13453 19560 bitmap_inited = true;
13454 }
13455 40410 bitmap_set_bit(&column_map, i);
13456 }
13457 }
13458
2/2
✓ Branch 0 taken 19560 times.
✓ Branch 1 taken 20879116 times.
20898676 if (bitmap_inited) {
13459
1/2
✓ Branch 0 taken 19560 times.
✗ Branch 1 not taken.
19560 THD *const thd = my_core::thd_get_current_thd();
13460 39120 int ret = handler::my_eval_gcolumn_expr(
13461 thd, const_cast<TABLE *>(table), &column_map,
13462
1/2
✓ Branch 0 taken 19560 times.
✗ Branch 1 not taken.
19560 const_cast<uchar *>(table->record[0]), nullptr, nullptr);
13463
13464 19560 return ret;
13465 }
13466 20879116 return 0;
13467 }
13468
13469 /**
13470 Scan the Primary Key index entries and populate the new secondary keys.
13471 */
13472 443 int ha_rocksdb::inplace_populate_sk(
13473 TABLE *const new_table_arg,
13474 const std::unordered_set<std::shared_ptr<Rdb_key_def>> &indexes) {
13475
1/2
✓ Branch 0 taken 443 times.
✗ Branch 1 not taken.
443 DBUG_ENTER_FUNC();
13476 443 int res = HA_EXIT_SUCCESS;
13477
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 443 times.
443 assert(indexes.size() > 0);
13478
1/2
✓ Branch 0 taken 443 times.
✗ Branch 1 not taken.
443 uint table_default_cf_id = (*indexes.begin())->get_cf()->GetID();
13479 auto local_dict_manager =
13480
1/2
✓ Branch 0 taken 443 times.
✗ Branch 1 not taken.
443 dict_manager.get_dict_manager_selector_non_const(table_default_cf_id);
13481
1/2
✓ Branch 0 taken 443 times.
✗ Branch 1 not taken.
443 const std::unique_ptr<rocksdb::WriteBatch> wb = local_dict_manager->begin();
13482 443 rocksdb::WriteBatch *const batch = wb.get();
13483
13484
6/10
✓ Branch 0 taken 443 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 440 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
443 DBUG_EXECUTE_IF("rocksdb_inplace_populate_sk", {
13485 static constexpr char act[] =
13486 "now signal ready_to_mark_cf_dropped_in_populate_sk "
13487 "wait_for mark_cf_dropped_done_in_populate_sk";
13488 assert(!debug_sync_set_action(ha_thd(), STRING_WITH_LEN(act)));
13489 });
13490
13491 {
13492
1/2
✓ Branch 0 taken 443 times.
✗ Branch 1 not taken.
443 std::lock_guard<Rdb_dict_manager> dm_lock(*local_dict_manager);
13493
2/2
✓ Branch 0 taken 463 times.
✓ Branch 1 taken 440 times.
903 for (const auto &kd : indexes) {
13494
2/4
✓ Branch 0 taken 463 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 463 times.
✗ Branch 3 not taken.
463 const std::string cf_name = kd->get_cf()->GetName();
13495 std::shared_ptr<rocksdb::ColumnFamilyHandle> cfh =
13496
1/2
✓ Branch 0 taken 463 times.
✗ Branch 1 not taken.
463 cf_manager.get_cf(cf_name);
13497
13498
4/8
✓ Branch 0 taken 463 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 463 times.
✓ Branch 4 taken 463 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 463 times.
463 if (!cfh || cfh != kd->get_shared_cf()) {
13499 // The CF has been dropped, i.e., cf_manager.remove_dropped_cf() has
13500 // been called.
13501 DBUG_RETURN(HA_EXIT_FAILURE);
13502 }
13503
13504
1/2
✓ Branch 0 taken 463 times.
✗ Branch 1 not taken.
463 uint32 cf_id = cfh->GetID();
13505
3/4
✓ Branch 0 taken 463 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 460 times.
463 if (local_dict_manager->get_dropped_cf(cf_id)) {
13506
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(HA_EXIT_FAILURE);
13507 }
13508
4/4
✓ Branch 0 taken 460 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 460 times.
✓ Branch 3 taken 3 times.
466 }
13509
13510 /* Update the data dictionary */
13511 440 std::unordered_set<GL_INDEX_ID> create_index_ids;
13512
2/2
✓ Branch 0 taken 460 times.
✓ Branch 1 taken 440 times.
900 for (const auto &index : indexes) {
13513
2/4
✓ Branch 0 taken 460 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 460 times.
✗ Branch 3 not taken.
460 create_index_ids.insert(index->get_gl_index_id());
13514 }
13515
1/2
✓ Branch 0 taken 440 times.
✗ Branch 1 not taken.
440 local_dict_manager->add_create_index(create_index_ids, batch);
13516
1/2
✓ Branch 0 taken 440 times.
✗ Branch 1 not taken.
440 res = local_dict_manager->commit(batch);
13517
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 440 times.
440 if (res != HA_EXIT_SUCCESS) {
13518 return res;
13519 }
13520
13521 /*
13522 Add uncommitted key definitons to ddl_manager. We need to do this
13523 so that the property collector can find this keydef when it needs to
13524 update stats. The property collector looks for the keydef in the
13525 data dictionary, but it won't be there yet since this key definition
13526 is still in the creation process.
13527 */
13528
1/2
✓ Branch 0 taken 440 times.
✗ Branch 1 not taken.
440 ddl_manager.add_uncommitted_keydefs(indexes);
13529
3/4
✓ Branch 0 taken 440 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 440 times.
✓ Branch 3 taken 3 times.
443 }
13530
13531
1/2
✓ Branch 0 taken 440 times.
✗ Branch 1 not taken.
440 const bool hidden_pk_exists = has_hidden_pk(table);
13532
13533
1/2
✓ Branch 0 taken 440 times.
✗ Branch 1 not taken.
440 Rdb_transaction *tx = get_or_create_tx(table->in_use);
13534
13535 /*
13536 There is one specific scenario where m_sst_info may not be nullptr. This
13537 happens if the handler we're using happens to be the handler where the PK
13538 bulk load was done on. The sequence of events that lead to this is as
13539 follows (T1 is PK bulk load, T2 is SK alter table):
13540
13541 T1: Execute last INSERT statement
13542 T1: Return TABLE and handler object back to Table_cache_manager
13543 T1: Close connection
13544 T2: Execute ALTER statement
13545 T2: Take same TABLE/handler from Table_cache_manager
13546 T2: Call closefrm which will call finalize_bulk_load on every other open
13547 table/handler *except* the one it's on.
13548 T2: Acquire stale snapshot of PK
13549 T1: Call finalize_bulk_load
13550
13551 This is rare because usually, closefrm will call the destructor (and thus
13552 finalize_bulk_load) on the handler where PK bulk load is done. However, if
13553 the thread ids of the bulk load thread and the alter thread differ by a
13554 multiple of table_cache_instances (8 by default), then they hash to the
13555 same bucket in Table_cache_manager and the alter thread will not not call
13556 the destructor on the handler it is holding. Thus, its m_sst_info will not
13557 be nullptr.
13558
13559 At this point, it is safe to refresh the snapshot because we know all other
13560 open handlers have been closed at this point, and the one we're on is the
13561 only one left.
13562 */
13563
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 439 times.
440 if (m_sst_info) {
13564
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if ((res = finalize_bulk_load())) {
13565 DBUG_RETURN(res);
13566 }
13567
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 assert(tx->get_write_count() == 0);
13568
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 tx->release_snapshot();
13569 }
13570
13571
2/2
✓ Branch 0 taken 460 times.
✓ Branch 1 taken 437 times.
897 for (const auto &index : indexes) {
13572 // Skip populating partial indexes.
13573
6/10
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 439 times.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 21 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 460 times.
460 if (index->is_partial_index() && !THDVAR(ha_thd(), bulk_load_partial_index))
13574 continue;
13575
13576 /*
13577 Note: We use the currently existing table + tbl_def object here,
13578 as the pk index position may have changed in the case of hidden primary
13579 keys.
13580 */
13581
1/2
✓ Branch 0 taken 460 times.
✗ Branch 1 not taken.
460 res = ha_rnd_init(true /* scan */);
13582
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 460 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
463 if (res) DBUG_RETURN(res);
13583
13584 /* Scan each record in the primary key in order */
13585
3/4
✓ Branch 0 taken 460 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4579203 times.
✓ Branch 3 taken 457 times.
4579660 for (res = ha_rnd_next(table->record[0]); res == 0;
13586
1/2
✓ Branch 0 taken 4579200 times.
✗ Branch 1 not taken.
4579200 res = ha_rnd_next(table->record[0])) {
13587 4579203 longlong hidden_pk_id = 0;
13588
3/4
✓ Branch 0 taken 15597 times.
✓ Branch 1 taken 4563606 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4579203 times.
4594800 if (hidden_pk_exists &&
13589
2/4
✓ Branch 0 taken 15597 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15597 times.
15597 (res = read_hidden_pk_id_from_rowkey(&hidden_pk_id))) {
13590 LogPluginErrMsg(ERROR_LEVEL, 0, "Error retrieving hidden pk id.");
13591 ha_rnd_end();
13592
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
3 DBUG_RETURN(res);
13593 }
13594
13595
2/4
✓ Branch 0 taken 4579203 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4579203 times.
4579203 if ((res = fill_virtual_columns())) {
13596 ha_rnd_end();
13597 DBUG_RETURN(res);
13598 }
13599
13600 /* Create new secondary index entry */
13601 4579203 const int new_packed_size = index->pack_record(
13602
1/2
✓ Branch 0 taken 4579203 times.
✗ Branch 1 not taken.
4579203 new_table_arg, m_pack_buffer, table->record[0], m_sk_packed_tuple,
13603 4579203 &m_sk_tails, should_store_row_debug_checksums(), hidden_pk_id, 0,
13604 4579203 nullptr, m_ttl_bytes);
13605
13606 const rocksdb::Slice key = rocksdb::Slice(
13607 4579203 reinterpret_cast<const char *>(m_sk_packed_tuple), new_packed_size);
13608 const rocksdb::Slice val =
13609 4579203 rocksdb::Slice(reinterpret_cast<const char *>(m_sk_tails.ptr()),
13610 9158406 m_sk_tails.get_current_pos());
13611
13612 /*
13613 Add record to offset tree in preparation for writing out to
13614 disk in sorted chunks.
13615 */
13616
3/4
✓ Branch 0 taken 4579203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 4579200 times.
4579203 if ((res = bulk_load_key(tx, *index, key, val, true))) {
13617
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 ha_rnd_end();
13618
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_RETURN(res);
13619 }
13620 }
13621
13622
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 457 times.
457 if (res != HA_ERR_END_OF_FILE) {
13623 LogPluginErrMsg(ERROR_LEVEL, 0,
13624 "Error retrieving index entry from primary key.");
13625 ha_rnd_end();
13626 DBUG_RETURN(res);
13627 }
13628
13629
1/2
✓ Branch 0 taken 457 times.
✗ Branch 1 not taken.
457 ha_rnd_end();
13630
13631 bool is_critical_error;
13632 914 res = tx->finish_bulk_load(&is_critical_error, true, new_table_arg,
13633
1/2
✓ Branch 0 taken 457 times.
✗ Branch 1 not taken.
457 m_table_handler->m_table_name);
13634
13635
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 442 times.
457 if (res == ER_DUP_ENTRY) {
13636
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 assert(new_table_arg->key_info[index->get_keyno()].flags & HA_NOSAME);
13637 15 print_keydup_error(new_table_arg,
13638
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 &new_table_arg->key_info[index->get_keyno()], MYF(0));
13639 }
13640
13641
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 439 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
457 if (res && is_critical_error) {
13642 LogPluginErrMsg(ERROR_LEVEL, 0, "Error finishing bulk load.");
13643 DBUG_RETURN(res);
13644 }
13645 }
13646
13647 /*
13648 Explicitly tell jemalloc to clean up any unused dirty pages at this point.
13649 See https://reviews.facebook.net/D63723 for more details.
13650 */
13651 437 purge_all_jemalloc_arenas();
13652
13653
4/6
✓ Branch 0 taken 437 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 434 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
437 DBUG_EXECUTE_IF("crash_during_online_index_creation", DBUG_SUICIDE(););
13654
1/2
✓ Branch 0 taken 434 times.
✗ Branch 1 not taken.
434 DBUG_RETURN(res);
13655 440 }
13656
13657 /**
13658 Commit or rollback the changes made during prepare_inplace_alter_table()
13659 and inplace_alter_table() inside the storage engine.
13660 Note that in case of rollback the allowed level of concurrency during
13661 this operation will be the same as for inplace_alter_table() and thus
13662 might be higher than during prepare_inplace_alter_table(). (For example,
13663 concurrent writes were blocked during prepare, but might not be during
13664 rollback).
13665
13666 @note Storage engines are responsible for reporting any errors by
13667 calling my_error()/print_error()
13668
13669 @note If this function with commit= true reports error, it will be called
13670 again with commit= false.
13671
13672 @note In case of partitioning, this function might be called for rollback
13673 without prepare_inplace_alter_table() having been called first.
13674 Also partitioned tables sets ha_alter_info->group_commit_ctx to a NULL
13675 terminated array of the partitions handlers and if all of them are
13676 committed as one, then group_commit_ctx should be set to NULL to indicate
13677 to the partitioning handler that all partitions handlers are committed.
13678 @see prepare_inplace_alter_table().
13679
13680 @param altered_table TABLE object for new version of table.
13681 @param ha_alter_info Structure describing changes to be done
13682 by ALTER TABLE and holding data used
13683 during in-place alter.
13684 @param commit True => Commit, False => Rollback.
13685
13686 @retval true Error
13687 @retval false Success
13688 */
13689 844 bool ha_rocksdb::commit_inplace_alter_table(
13690 my_core::TABLE *altered_table, my_core::Alter_inplace_info *ha_alter_info,
13691 bool commit, const dd::Table *old_table_def MY_ATTRIBUTE((__unused__)),
13692 dd::Table *new_table_def MY_ATTRIBUTE((__unused__))) {
13693
1/2
✓ Branch 0 taken 844 times.
✗ Branch 1 not taken.
844 DBUG_ENTER_FUNC();
13694
13695
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 844 times.
844 assert(altered_table != nullptr);
13696
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 844 times.
844 assert(ha_alter_info != nullptr);
13697
13698 844 Rdb_inplace_alter_ctx *const ctx0 =
13699 static_cast<Rdb_inplace_alter_ctx *>(ha_alter_info->handler_ctx);
13700
13701
3/6
✓ Branch 0 taken 844 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 844 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 844 times.
✗ Branch 5 not taken.
844 DEBUG_SYNC(ha_thd(), "rocksdb.commit_in_place_alter_table");
13702
13703 /*
13704 IMPORTANT: When rollback is requested, mysql will abort with
13705 an assertion failure. That means every failed commit during inplace alter
13706 table will result in a fatal error on the server. Indexes ongoing creation
13707 will be detected when the server restarts, and dropped.
13708
13709 For partitioned tables, a rollback call to this function (commit == false)
13710 is done for each partition. A successful commit call only executes once
13711 for all partitions.
13712 */
13713
2/2
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 564 times.
844 if (!commit) {
13714 /* If ctx has not been created yet, nothing to do here */
13715
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 268 times.
280 if (!ctx0) {
13716
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 DBUG_RETURN(HA_EXIT_SUCCESS);
13717 }
13718
13719 /*
13720 Cannot call destructor for Rdb_tbl_def directly because we don't want to
13721 erase the mappings inside the ddl_manager, as the old_key_descr is still
13722 using them.
13723 */
13724
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 240 times.
268 if (ctx0->m_new_key_descr) {
13725 /* Delete the new key descriptors */
13726
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 28 times.
91 for (uint i = 0; i < ctx0->m_new_tdef->m_key_count; i++) {
13727 63 ctx0->m_new_key_descr[i] = nullptr;
13728 }
13729
13730
3/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 28 times.
91 delete[] ctx0->m_new_key_descr;
13731 28 ctx0->m_new_key_descr = nullptr;
13732 28 ctx0->m_new_tdef->m_key_descr_arr = nullptr;
13733
13734
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 delete ctx0->m_new_tdef;
13735 }
13736
13737
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 240 times.
268 if (!ctx0->m_added_indexes.empty()) {
13738 28 auto first_index = ctx0->m_added_indexes.begin();
13739 auto local_dict_manager =
13740
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 dict_manager.get_dict_manager_selector_non_const(
13741
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 (*first_index)->get_gl_index_id().cf_id);
13742
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 std::lock_guard<Rdb_dict_manager> dm_lock(*local_dict_manager);
13743 /* Remove uncommitted key definitons from ddl_manager */
13744
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 ddl_manager.remove_uncommitted_keydefs(ctx0->m_added_indexes);
13745
13746 28 std::unordered_set<GL_INDEX_ID> all_gl_index_ids;
13747
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 local_dict_manager->get_ongoing_create_indexes(&all_gl_index_ids);
13748
13749 28 std::unordered_set<GL_INDEX_ID> gl_index_ids;
13750
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 28 times.
59 for (auto index : ctx0->m_added_indexes) {
13751
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 auto gl_index_id = index->get_gl_index_id();
13752
3/4
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 6 times.
31 if (all_gl_index_ids.find(gl_index_id) != all_gl_index_ids.end()) {
13753
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 gl_index_ids.insert(gl_index_id);
13754 }
13755 31 }
13756
13757
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 6 times.
28 if (!gl_index_ids.empty()) {
13758 /* Rollback any partially created indexes of this table */
13759
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 local_dict_manager->rollback_ongoing_index_creation(gl_index_ids);
13760 }
13761 28 }
13762
13763
1/2
✓ Branch 0 taken 268 times.
✗ Branch 1 not taken.
268 DBUG_RETURN(HA_EXIT_SUCCESS);
13764 }
13765
13766
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 564 times.
564 assert(ctx0);
13767
13768 /*
13769 For partitioned tables, we need to commit all changes to all tables at
13770 once, unlike in the other inplace alter API methods.
13771 */
13772 inplace_alter_handler_ctx **ctx_array;
13773 inplace_alter_handler_ctx *ctx_single[2];
13774
13775
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 475 times.
564 if (ha_alter_info->group_commit_ctx) {
13776
4/6
✓ Branch 0 taken 89 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 86 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
89 DBUG_EXECUTE_IF("crash_during_index_creation_partition", DBUG_SUICIDE(););
13777 86 ctx_array = ha_alter_info->group_commit_ctx;
13778 } else {
13779 475 ctx_single[0] = ctx0;
13780 475 ctx_single[1] = nullptr;
13781 475 ctx_array = ctx_single;
13782 }
13783
13784
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 561 times.
561 assert(ctx0 == ctx_array[0]);
13785 561 ha_alter_info->group_commit_ctx = nullptr;
13786 uint table_default_cf_id =
13787
1/2
✓ Branch 0 taken 561 times.
✗ Branch 1 not taken.
561 m_tbl_def->m_key_descr_arr[0]->get_gl_index_id().cf_id;
13788
2/2
✓ Branch 0 taken 414 times.
✓ Branch 1 taken 147 times.
561 if (ha_alter_info->handler_flags &
13789 (my_core::Alter_inplace_info::DROP_INDEX |
13790 my_core::Alter_inplace_info::DROP_UNIQUE_INDEX |
13791 my_core::Alter_inplace_info::ADD_INDEX |
13792 my_core::Alter_inplace_info::ADD_UNIQUE_INDEX)) {
13793 auto local_dict_manager =
13794
1/2
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
414 dict_manager.get_dict_manager_selector_non_const(table_default_cf_id);
13795
1/2
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
414 const std::unique_ptr<rocksdb::WriteBatch> wb = local_dict_manager->begin();
13796 414 rocksdb::WriteBatch *const batch = wb.get();
13797 414 std::unordered_set<GL_INDEX_ID> create_index_ids;
13798
13799 414 m_tbl_def = ctx0->m_new_tdef;
13800 414 m_key_descr_arr = m_tbl_def->m_key_descr_arr;
13801
1/2
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
414 m_pk_descr = m_key_descr_arr[pk_index(altered_table, m_tbl_def)];
13802
13803
6/10
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 411 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
414 DBUG_EXECUTE_IF("rocksdb_commit_alter_table", {
13804 static constexpr char act[] =
13805 "now signal ready_to_mark_cf_dropped_before_commit_alter_table "
13806 "wait_for mark_cf_dropped_done_before_commit_alter_table";
13807 assert(!debug_sync_set_action(ha_thd(), STRING_WITH_LEN(act)));
13808 });
13809
13810 {
13811
1/2
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
414 std::lock_guard<Rdb_dict_manager> dm_lock(*local_dict_manager);
13812
2/2
✓ Branch 0 taken 546 times.
✓ Branch 1 taken 414 times.
960 for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx; pctx++) {
13813 546 Rdb_inplace_alter_ctx *const ctx =
13814 static_cast<Rdb_inplace_alter_ctx *>(*pctx);
13815
13816 /* Mark indexes to be dropped */
13817
1/2
✓ Branch 0 taken 546 times.
✗ Branch 1 not taken.
546 local_dict_manager->add_drop_index(ctx->m_dropped_index_ids, batch);
13818
13819
2/2
✓ Branch 0 taken 420 times.
✓ Branch 1 taken 546 times.
966 for (const auto &index : ctx->m_added_indexes) {
13820
2/4
✓ Branch 0 taken 420 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 420 times.
✗ Branch 3 not taken.
420 create_index_ids.insert(index->get_gl_index_id());
13821 }
13822
13823
2/4
✓ Branch 0 taken 546 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 546 times.
546 if (ddl_manager.put_and_write(ctx->m_new_tdef, batch)) {
13824 /*
13825 Failed to write new entry into data dictionary, this should never
13826 happen.
13827 */
13828 assert(0);
13829 }
13830
13831 /*
13832 Remove uncommitted key definitons from ddl_manager, as they are now
13833 committed into the data dictionary.
13834 */
13835
1/2
✓ Branch 0 taken 546 times.
✗ Branch 1 not taken.
546 ddl_manager.remove_uncommitted_keydefs(ctx->m_added_indexes);
13836 }
13837
13838
2/4
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 414 times.
414 if (local_dict_manager->commit(batch)) {
13839 /*
13840 Should never reach here. We assume MyRocks will abort if commit
13841 fails.
13842 */
13843 assert(0);
13844 }
13845
13846 /* Mark ongoing create indexes as finished/remove from data dictionary */
13847
1/2
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
414 local_dict_manager->finish_indexes_operation(
13848 create_index_ids, Rdb_key_def::DDL_CREATE_INDEX_ONGOING);
13849 414 }
13850
13851
6/10
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 411 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
414 DBUG_EXECUTE_IF("rocksdb_delete_index", {
13852 static constexpr char act[] =
13853 "now signal ready_to_mark_cf_dropped_after_commit_alter_table "
13854 "wait_for mark_cf_dropped_done_after_commit_alter_table";
13855 assert(!debug_sync_set_action(ha_thd(), STRING_WITH_LEN(act)));
13856 });
13857
13858
1/2
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
414 rdb_drop_idx_thread.signal();
13859
13860
4/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 411 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 414 times.
414 if (rocksdb_table_stats_use_table_scan && !ctx0->m_added_indexes.empty()) {
13861 // If new indexes are created, add the table to the recalc queue
13862 // to calculate stats for new indexes
13863 rdb_is_thread.add_index_stats_request(m_tbl_def->full_tablename());
13864 }
13865 414 }
13866
13867
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 507 times.
561 if (ha_alter_info->handler_flags &
13868 (my_core::Alter_inplace_info::CHANGE_CREATE_OPTION)) {
13869 auto local_dict_manager =
13870
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 dict_manager.get_dict_manager_selector_non_const(table_default_cf_id);
13871
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 const std::unique_ptr<rocksdb::WriteBatch> wb = local_dict_manager->begin();
13872 54 rocksdb::WriteBatch *const batch = wb.get();
13873 54 std::unordered_set<GL_INDEX_ID> create_index_ids;
13874
13875 54 ulonglong auto_incr_val = ha_alter_info->create_info->auto_increment_value;
13876
13877
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 54 times.
144 for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx; pctx++) {
13878 90 Rdb_inplace_alter_ctx *const ctx =
13879 static_cast<Rdb_inplace_alter_ctx *>(*pctx);
13880 90 auto_incr_val = std::max(auto_incr_val, ctx->m_max_auto_incr);
13881
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 local_dict_manager->put_auto_incr_val(
13882
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 batch, ctx->m_new_tdef->get_autoincr_gl_index_id(), auto_incr_val,
13883 true /* overwrite */);
13884 90 ctx->m_new_tdef->m_auto_incr_val = auto_incr_val;
13885 }
13886
13887
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
54 if (local_dict_manager->commit(batch)) {
13888 assert(0);
13889 }
13890 54 }
13891
13892
1/2
✓ Branch 0 taken 561 times.
✗ Branch 1 not taken.
561 DBUG_RETURN(HA_EXIT_SUCCESS);
13893 }
13894
13895 #define SHOW_FNAME(name) rocksdb_show_##name
13896
13897 #define DEF_SHOW_FUNC(name, key) \
13898 static int SHOW_FNAME(name)(MYSQL_THD thd, SHOW_VAR * var, char *buff) { \
13899 rocksdb_status_counters.name = \
13900 rocksdb_stats->getTickerCount(rocksdb::key); \
13901 var->type = SHOW_LONGLONG; \
13902 var->value = (char *)&rocksdb_status_counters.name; \
13903 return HA_EXIT_SUCCESS; \
13904 }
13905
13906 #define DEF_STATUS_VAR(name) \
13907 { "rocksdb_" #name, (char *)&SHOW_FNAME(name), SHOW_FUNC, SHOW_SCOPE_GLOBAL }
13908
13909 #define DEF_STATUS_VAR_PTR(name, ptr, option) \
13910 { "rocksdb_" name, (char *)ptr, option, SHOW_SCOPE_GLOBAL }
13911
13912 #define DEF_STATUS_VAR_FUNC(name, ptr, option) \
13913 { name, reinterpret_cast<char *>(ptr), option, SHOW_SCOPE_GLOBAL }
13914
13915 struct rocksdb_status_counters_t {
13916 uint64_t block_cache_miss;
13917 uint64_t block_cache_hit;
13918 uint64_t block_cache_add;
13919 uint64_t block_cache_add_failures;
13920 uint64_t block_cache_index_miss;
13921 uint64_t block_cache_index_hit;
13922 uint64_t block_cache_index_add;
13923 uint64_t block_cache_index_bytes_insert;
13924 uint64_t block_cache_index_bytes_evict;
13925 uint64_t block_cache_filter_miss;
13926 uint64_t block_cache_filter_hit;
13927 uint64_t block_cache_filter_add;
13928 uint64_t block_cache_filter_bytes_insert;
13929 uint64_t block_cache_filter_bytes_evict;
13930 uint64_t block_cache_bytes_read;
13931 uint64_t block_cache_bytes_write;
13932 uint64_t block_cache_data_bytes_insert;
13933 uint64_t block_cache_data_miss;
13934 uint64_t block_cache_data_hit;
13935 uint64_t block_cache_data_add;
13936 uint64_t bloom_filter_useful;
13937 uint64_t bloom_filter_full_positive;
13938 uint64_t bloom_filter_full_true_positive;
13939 uint64_t memtable_hit;
13940 uint64_t memtable_miss;
13941 uint64_t get_hit_l0;
13942 uint64_t get_hit_l1;
13943 uint64_t get_hit_l2_and_up;
13944 uint64_t compaction_key_drop_new;
13945 uint64_t compaction_key_drop_obsolete;
13946 uint64_t compaction_key_drop_user;
13947 uint64_t number_keys_written;
13948 uint64_t number_keys_read;
13949 uint64_t number_keys_updated;
13950 uint64_t bytes_written;
13951 uint64_t bytes_read;
13952 uint64_t number_db_seek;
13953 uint64_t number_db_seek_found;
13954 uint64_t number_db_next;
13955 uint64_t number_db_next_found;
13956 uint64_t number_db_prev;
13957 uint64_t number_db_prev_found;
13958 uint64_t iter_bytes_read;
13959 uint64_t no_file_closes;
13960 uint64_t no_file_opens;
13961 uint64_t no_file_errors;
13962 uint64_t stall_micros;
13963 uint64_t num_iterators;
13964 uint64_t number_multiget_get;
13965 uint64_t number_multiget_keys_read;
13966 uint64_t number_multiget_bytes_read;
13967 uint64_t number_deletes_filtered;
13968 uint64_t number_merge_failures;
13969 uint64_t bloom_filter_prefix_checked;
13970 uint64_t bloom_filter_prefix_useful;
13971 uint64_t number_reseeks_iteration;
13972 uint64_t get_updates_since_calls;
13973 uint64_t block_cache_compressed_miss;
13974 uint64_t block_cache_compressed_hit;
13975 uint64_t wal_synced;
13976 uint64_t wal_bytes;
13977 uint64_t write_self;
13978 uint64_t write_other;
13979 uint64_t write_timedout;
13980 uint64_t write_wal;
13981 uint64_t flush_write_bytes;
13982 uint64_t compact_read_bytes;
13983 uint64_t compact_write_bytes;
13984 uint64_t number_superversion_acquires;
13985 uint64_t number_superversion_releases;
13986 uint64_t number_superversion_cleanups;
13987 uint64_t number_block_not_compressed;
13988 };
13989
13990 static rocksdb_status_counters_t rocksdb_status_counters;
13991
13992 11912 DEF_SHOW_FUNC(block_cache_miss, BLOCK_CACHE_MISS)
13993 11912 DEF_SHOW_FUNC(block_cache_hit, BLOCK_CACHE_HIT)
13994 11912 DEF_SHOW_FUNC(block_cache_add, BLOCK_CACHE_ADD)
13995 11912 DEF_SHOW_FUNC(block_cache_add_failures, BLOCK_CACHE_ADD_FAILURES)
13996 11912 DEF_SHOW_FUNC(block_cache_index_miss, BLOCK_CACHE_INDEX_MISS)
13997 11912 DEF_SHOW_FUNC(block_cache_index_hit, BLOCK_CACHE_INDEX_HIT)
13998 11912 DEF_SHOW_FUNC(block_cache_index_add, BLOCK_CACHE_INDEX_ADD)
13999 11912 DEF_SHOW_FUNC(block_cache_index_bytes_insert, BLOCK_CACHE_INDEX_BYTES_INSERT)
14000 11912 DEF_SHOW_FUNC(block_cache_index_bytes_evict, BLOCK_CACHE_INDEX_BYTES_EVICT)
14001 11912 DEF_SHOW_FUNC(block_cache_filter_miss, BLOCK_CACHE_FILTER_MISS)
14002 11912 DEF_SHOW_FUNC(block_cache_filter_hit, BLOCK_CACHE_FILTER_HIT)
14003 11912 DEF_SHOW_FUNC(block_cache_filter_add, BLOCK_CACHE_FILTER_ADD)
14004 11912 DEF_SHOW_FUNC(block_cache_filter_bytes_insert, BLOCK_CACHE_FILTER_BYTES_INSERT)
14005 11912 DEF_SHOW_FUNC(block_cache_filter_bytes_evict, BLOCK_CACHE_FILTER_BYTES_EVICT)
14006 11912 DEF_SHOW_FUNC(block_cache_bytes_read, BLOCK_CACHE_BYTES_READ)
14007 11912 DEF_SHOW_FUNC(block_cache_bytes_write, BLOCK_CACHE_BYTES_WRITE)
14008 11912 DEF_SHOW_FUNC(block_cache_data_bytes_insert, BLOCK_CACHE_DATA_BYTES_INSERT)
14009 11912 DEF_SHOW_FUNC(block_cache_data_miss, BLOCK_CACHE_DATA_MISS)
14010 11912 DEF_SHOW_FUNC(block_cache_data_hit, BLOCK_CACHE_DATA_HIT)
14011 11912 DEF_SHOW_FUNC(block_cache_data_add, BLOCK_CACHE_DATA_ADD)
14012 11912 DEF_SHOW_FUNC(bloom_filter_useful, BLOOM_FILTER_USEFUL)
14013 11912 DEF_SHOW_FUNC(bloom_filter_full_positive, BLOOM_FILTER_FULL_POSITIVE)
14014 11912 DEF_SHOW_FUNC(bloom_filter_full_true_positive, BLOOM_FILTER_FULL_TRUE_POSITIVE)
14015 11912 DEF_SHOW_FUNC(memtable_hit, MEMTABLE_HIT)
14016 11912 DEF_SHOW_FUNC(memtable_miss, MEMTABLE_MISS)
14017 11912 DEF_SHOW_FUNC(get_hit_l0, GET_HIT_L0)
14018 11912 DEF_SHOW_FUNC(get_hit_l1, GET_HIT_L1)
14019 11912 DEF_SHOW_FUNC(get_hit_l2_and_up, GET_HIT_L2_AND_UP)
14020 11912 DEF_SHOW_FUNC(compaction_key_drop_new, COMPACTION_KEY_DROP_NEWER_ENTRY)
14021 11912 DEF_SHOW_FUNC(compaction_key_drop_obsolete, COMPACTION_KEY_DROP_OBSOLETE)
14022 11912 DEF_SHOW_FUNC(compaction_key_drop_user, COMPACTION_KEY_DROP_USER)
14023 11912 DEF_SHOW_FUNC(number_keys_written, NUMBER_KEYS_WRITTEN)
14024 11912 DEF_SHOW_FUNC(number_keys_read, NUMBER_KEYS_READ)
14025 11912 DEF_SHOW_FUNC(number_keys_updated, NUMBER_KEYS_UPDATED)
14026 11912 DEF_SHOW_FUNC(bytes_written, BYTES_WRITTEN)
14027 11912 DEF_SHOW_FUNC(bytes_read, BYTES_READ)
14028 11912 DEF_SHOW_FUNC(number_db_seek, NUMBER_DB_SEEK)
14029 11912 DEF_SHOW_FUNC(number_db_seek_found, NUMBER_DB_SEEK_FOUND)
14030 11912 DEF_SHOW_FUNC(number_db_next, NUMBER_DB_NEXT)
14031 11912 DEF_SHOW_FUNC(number_db_next_found, NUMBER_DB_NEXT_FOUND)
14032 11912 DEF_SHOW_FUNC(number_db_prev, NUMBER_DB_PREV)
14033 11912 DEF_SHOW_FUNC(number_db_prev_found, NUMBER_DB_PREV_FOUND)
14034 11912 DEF_SHOW_FUNC(iter_bytes_read, ITER_BYTES_READ)
14035 11912 DEF_SHOW_FUNC(no_file_closes, NO_FILE_CLOSES)
14036 11912 DEF_SHOW_FUNC(no_file_opens, NO_FILE_OPENS)
14037 11912 DEF_SHOW_FUNC(no_file_errors, NO_FILE_ERRORS)
14038 11912 DEF_SHOW_FUNC(stall_micros, STALL_MICROS)
14039 11912 DEF_SHOW_FUNC(num_iterators, NO_ITERATORS)
14040 11912 DEF_SHOW_FUNC(number_multiget_get, NUMBER_MULTIGET_CALLS)
14041 11912 DEF_SHOW_FUNC(number_multiget_keys_read, NUMBER_MULTIGET_KEYS_READ)
14042 11912 DEF_SHOW_FUNC(number_multiget_bytes_read, NUMBER_MULTIGET_BYTES_READ)
14043 11912 DEF_SHOW_FUNC(number_deletes_filtered, NUMBER_FILTERED_DELETES)
14044 11912 DEF_SHOW_FUNC(number_merge_failures, NUMBER_MERGE_FAILURES)
14045 11912 DEF_SHOW_FUNC(bloom_filter_prefix_checked, BLOOM_FILTER_PREFIX_CHECKED)
14046 11912 DEF_SHOW_FUNC(bloom_filter_prefix_useful, BLOOM_FILTER_PREFIX_USEFUL)
14047 11912 DEF_SHOW_FUNC(number_reseeks_iteration, NUMBER_OF_RESEEKS_IN_ITERATION)
14048 11912 DEF_SHOW_FUNC(get_updates_since_calls, GET_UPDATES_SINCE_CALLS)
14049 11912 DEF_SHOW_FUNC(block_cache_compressed_miss, BLOCK_CACHE_COMPRESSED_MISS)
14050 11912 DEF_SHOW_FUNC(block_cache_compressed_hit, BLOCK_CACHE_COMPRESSED_HIT)
14051 11912 DEF_SHOW_FUNC(wal_synced, WAL_FILE_SYNCED)
14052 11912 DEF_SHOW_FUNC(wal_bytes, WAL_FILE_BYTES)
14053 11912 DEF_SHOW_FUNC(write_self, WRITE_DONE_BY_SELF)
14054 11912 DEF_SHOW_FUNC(write_other, WRITE_DONE_BY_OTHER)
14055 11912 DEF_SHOW_FUNC(write_timedout, WRITE_TIMEDOUT)
14056 11912 DEF_SHOW_FUNC(write_wal, WRITE_WITH_WAL)
14057 11912 DEF_SHOW_FUNC(flush_write_bytes, FLUSH_WRITE_BYTES)
14058 11912 DEF_SHOW_FUNC(compact_read_bytes, COMPACT_READ_BYTES)
14059 11912 DEF_SHOW_FUNC(compact_write_bytes, COMPACT_WRITE_BYTES)
14060 11912 DEF_SHOW_FUNC(number_superversion_acquires, NUMBER_SUPERVERSION_ACQUIRES)
14061 11912 DEF_SHOW_FUNC(number_superversion_releases, NUMBER_SUPERVERSION_RELEASES)
14062 11912 DEF_SHOW_FUNC(number_superversion_cleanups, NUMBER_SUPERVERSION_CLEANUPS)
14063 11912 DEF_SHOW_FUNC(number_block_not_compressed, NUMBER_BLOCK_NOT_COMPRESSED)
14064
14065 11912 static void myrocks_update_status() {
14066 11912 export_stats.rows_deleted = global_stats.rows[ROWS_DELETED];
14067 11912 export_stats.rows_deleted_blind = global_stats.rows[ROWS_DELETED_BLIND];
14068 11912 export_stats.rows_inserted = global_stats.rows[ROWS_INSERTED];
14069 11912 export_stats.rows_read = global_stats.rows[ROWS_READ];
14070 11912 export_stats.rows_updated = global_stats.rows[ROWS_UPDATED];
14071 11912 export_stats.rows_expired = global_stats.rows[ROWS_EXPIRED];
14072 11912 export_stats.rows_filtered = global_stats.rows[ROWS_FILTERED];
14073 11912 export_stats.rows_unfiltered_no_snapshot =
14074 11912 global_stats.rows[ROWS_UNFILTERED_NO_SNAPSHOT];
14075
14076 11912 export_stats.system_rows_deleted = global_stats.system_rows[ROWS_DELETED];
14077 11912 export_stats.system_rows_inserted = global_stats.system_rows[ROWS_INSERTED];
14078 11912 export_stats.system_rows_read = global_stats.system_rows[ROWS_READ];
14079 11912 export_stats.system_rows_updated = global_stats.system_rows[ROWS_UPDATED];
14080
14081 11912 export_stats.queries_point = global_stats.queries[QUERIES_POINT];
14082 11912 export_stats.queries_range = global_stats.queries[QUERIES_RANGE];
14083
14084 11912 export_stats.table_index_stats_success =
14085 11912 global_stats.table_index_stats_result[TABLE_INDEX_STATS_SUCCESS];
14086 11912 export_stats.table_index_stats_failure =
14087 11912 global_stats.table_index_stats_result[TABLE_INDEX_STATS_FAILURE];
14088 11912 export_stats.table_index_stats_req_queue_length =
14089 11912 rdb_is_thread.get_request_queue_size();
14090
14091 11912 export_stats.covered_secondary_key_lookups =
14092 11912 global_stats.covered_secondary_key_lookups;
14093 11912 }
14094
14095 11912 static void myrocks_update_memory_status() {
14096 11912 std::vector<rocksdb::DB *> dbs;
14097 11912 std::unordered_set<const rocksdb::Cache *> cache_set;
14098
1/2
✓ Branch 0 taken 11912 times.
✗ Branch 1 not taken.
11912 dbs.push_back(rdb);
14099 11912 std::map<rocksdb::MemoryUtil::UsageType, uint64_t> temp_usage_by_type;
14100
2/4
✓ Branch 0 taken 11912 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11912 times.
✗ Branch 3 not taken.
11912 rocksdb::MemoryUtil::GetApproximateMemoryUsageByType(dbs, cache_set,
14101 &temp_usage_by_type);
14102 11912 memory_stats.memtable_total =
14103
1/2
✓ Branch 0 taken 11912 times.
✗ Branch 1 not taken.
11912 temp_usage_by_type[rocksdb::MemoryUtil::kMemTableTotal];
14104 11912 memory_stats.memtable_unflushed =
14105
1/2
✓ Branch 0 taken 11912 times.
✗ Branch 1 not taken.
11912 temp_usage_by_type[rocksdb::MemoryUtil::kMemTableUnFlushed];
14106 11912 }
14107
14108 static SHOW_VAR myrocks_status_variables[] = {
14109 DEF_STATUS_VAR_FUNC("rows_deleted", &export_stats.rows_deleted,
14110 SHOW_LONGLONG),
14111 DEF_STATUS_VAR_FUNC("rows_deleted_blind", &export_stats.rows_deleted_blind,
14112 SHOW_LONGLONG),
14113 DEF_STATUS_VAR_FUNC("rows_inserted", &export_stats.rows_inserted,
14114 SHOW_LONGLONG),
14115 DEF_STATUS_VAR_FUNC("rows_read", &export_stats.rows_read, SHOW_LONGLONG),
14116 DEF_STATUS_VAR_FUNC("rows_updated", &export_stats.rows_updated,
14117 SHOW_LONGLONG),
14118 DEF_STATUS_VAR_FUNC("rows_expired", &export_stats.rows_expired,
14119 SHOW_LONGLONG),
14120 DEF_STATUS_VAR_FUNC("rows_filtered", &export_stats.rows_filtered,
14121 SHOW_LONGLONG),
14122 DEF_STATUS_VAR_FUNC("rows_unfiltered_no_snapshot",
14123 &export_stats.rows_unfiltered_no_snapshot,
14124 SHOW_LONGLONG),
14125 DEF_STATUS_VAR_FUNC("system_rows_deleted",
14126 &export_stats.system_rows_deleted, SHOW_LONGLONG),
14127 DEF_STATUS_VAR_FUNC("system_rows_inserted",
14128 &export_stats.system_rows_inserted, SHOW_LONGLONG),
14129 DEF_STATUS_VAR_FUNC("system_rows_read", &export_stats.system_rows_read,
14130 SHOW_LONGLONG),
14131 DEF_STATUS_VAR_FUNC("system_rows_updated",
14132 &export_stats.system_rows_updated, SHOW_LONGLONG),
14133 DEF_STATUS_VAR_FUNC("memtable_total", &memory_stats.memtable_total,
14134 SHOW_LONGLONG),
14135 DEF_STATUS_VAR_FUNC("memtable_unflushed", &memory_stats.memtable_unflushed,
14136 SHOW_LONGLONG),
14137 DEF_STATUS_VAR_FUNC("queries_point", &export_stats.queries_point,
14138 SHOW_LONGLONG),
14139 DEF_STATUS_VAR_FUNC("queries_range", &export_stats.queries_range,
14140 SHOW_LONGLONG),
14141 DEF_STATUS_VAR_FUNC("table_index_stats_success",
14142 &export_stats.table_index_stats_success, SHOW_LONGLONG),
14143 DEF_STATUS_VAR_FUNC("table_index_stats_failure",
14144 &export_stats.table_index_stats_failure, SHOW_LONGLONG),
14145 DEF_STATUS_VAR_FUNC("table_index_stats_req_queue_length",
14146 &export_stats.table_index_stats_req_queue_length,
14147 SHOW_LONGLONG),
14148 DEF_STATUS_VAR_FUNC("covered_secondary_key_lookups",
14149 &export_stats.covered_secondary_key_lookups,
14150 SHOW_LONGLONG),
14151
14152 {NullS, NullS, SHOW_LONG, SHOW_SCOPE_GLOBAL}};
14153
14154 11912 static void show_myrocks_vars(THD *thd, SHOW_VAR *var, char *buff) {
14155 11912 myrocks_update_status();
14156 11912 myrocks_update_memory_status();
14157 11912 var->type = SHOW_ARRAY;
14158 11912 var->value = reinterpret_cast<char *>(&myrocks_status_variables);
14159 11912 }
14160
14161 552760 static ulonglong io_stall_prop_value(
14162 const std::map<std::string, std::string> &props, const std::string &key) {
14163 std::map<std::string, std::string>::const_iterator iter =
14164
2/4
✓ Branch 0 taken 552760 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 552760 times.
✗ Branch 3 not taken.
552760 props.find("io_stalls." + key);
14165
1/2
✓ Branch 0 taken 552760 times.
✗ Branch 1 not taken.
552760 if (iter != props.end()) {
14166
1/2
✓ Branch 0 taken 552760 times.
✗ Branch 1 not taken.
552760 return std::stoull(iter->second);
14167 } else {
14168 DBUG_PRINT("warning",
14169 ("RocksDB GetMapProperty hasn't returned key=%s", key.c_str()));
14170 assert(0);
14171 return 0;
14172 }
14173 }
14174
14175 11912 static void update_rocksdb_stall_status() {
14176 11912 st_io_stall_stats local_io_stall_stats;
14177
3/4
✓ Branch 0 taken 11912 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55276 times.
✓ Branch 3 taken 11912 times.
67188 for (const auto &cf_name : cf_manager.get_cf_names()) {
14178 std::shared_ptr<rocksdb::ColumnFamilyHandle> cfh =
14179
1/2
✓ Branch 0 taken 55276 times.
✗ Branch 1 not taken.
55276 cf_manager.get_cf(cf_name);
14180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55276 times.
55276 if (!cfh) {
14181 continue;
14182 }
14183
14184 // Retrieve information from valid CF handle object. It is safe
14185 // even if the CF is removed from cf_manager at this point.
14186 55276 std::map<std::string, std::string> props;
14187
2/4
✓ Branch 0 taken 55276 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 55276 times.
55276 if (!rdb->GetMapProperty(cfh.get(), "rocksdb.cfstats", &props)) {
14188 continue;
14189 }
14190
14191 55276 local_io_stall_stats.level0_slowdown +=
14192
2/4
✓ Branch 0 taken 55276 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55276 times.
✗ Branch 3 not taken.
55276 io_stall_prop_value(props, "level0_slowdown");
14193 55276 local_io_stall_stats.level0_slowdown_with_compaction +=
14194
2/4
✓ Branch 0 taken 55276 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55276 times.
✗ Branch 3 not taken.
55276 io_stall_prop_value(props, "level0_slowdown_with_compaction");
14195 55276 local_io_stall_stats.level0_numfiles +=
14196
2/4
✓ Branch 0 taken 55276 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55276 times.
✗ Branch 3 not taken.
55276 io_stall_prop_value(props, "level0_numfiles");
14197 55276 local_io_stall_stats.level0_numfiles_with_compaction +=
14198
2/4
✓ Branch 0 taken 55276 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55276 times.
✗ Branch 3 not taken.
55276 io_stall_prop_value(props, "level0_numfiles_with_compaction");
14199 55276 local_io_stall_stats.stop_for_pending_compaction_bytes +=
14200
2/4
✓ Branch 0 taken 55276 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55276 times.
✗ Branch 3 not taken.
55276 io_stall_prop_value(props, "stop_for_pending_compaction_bytes");
14201 55276 local_io_stall_stats.slowdown_for_pending_compaction_bytes +=
14202
2/4
✓ Branch 0 taken 55276 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55276 times.
✗ Branch 3 not taken.
55276 io_stall_prop_value(props, "slowdown_for_pending_compaction_bytes");
14203 55276 local_io_stall_stats.memtable_compaction +=
14204
2/4
✓ Branch 0 taken 55276 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55276 times.
✗ Branch 3 not taken.
55276 io_stall_prop_value(props, "memtable_compaction");
14205 55276 local_io_stall_stats.memtable_slowdown +=
14206
2/4
✓ Branch 0 taken 55276 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55276 times.
✗ Branch 3 not taken.
55276 io_stall_prop_value(props, "memtable_slowdown");
14207
2/4
✓ Branch 0 taken 55276 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55276 times.
✗ Branch 3 not taken.
55276 local_io_stall_stats.total_stop += io_stall_prop_value(props, "total_stop");
14208 55276 local_io_stall_stats.total_slowdown +=
14209
2/4
✓ Branch 0 taken 55276 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55276 times.
✗ Branch 3 not taken.
55276 io_stall_prop_value(props, "total_slowdown");
14210
2/4
✓ Branch 0 taken 55276 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55276 times.
✗ Branch 3 not taken.
67188 }
14211 11912 io_stall_stats = local_io_stall_stats;
14212 11912 }
14213
14214 static SHOW_VAR rocksdb_stall_status_variables[] = {
14215 DEF_STATUS_VAR_FUNC("l0_file_count_limit_slowdowns",
14216 &io_stall_stats.level0_slowdown, SHOW_LONGLONG),
14217 DEF_STATUS_VAR_FUNC("locked_l0_file_count_limit_slowdowns",
14218 &io_stall_stats.level0_slowdown_with_compaction,
14219 SHOW_LONGLONG),
14220 DEF_STATUS_VAR_FUNC("l0_file_count_limit_stops",
14221 &io_stall_stats.level0_numfiles, SHOW_LONGLONG),
14222 DEF_STATUS_VAR_FUNC("locked_l0_file_count_limit_stops",
14223 &io_stall_stats.level0_numfiles_with_compaction,
14224 SHOW_LONGLONG),
14225 DEF_STATUS_VAR_FUNC("pending_compaction_limit_stops",
14226 &io_stall_stats.stop_for_pending_compaction_bytes,
14227 SHOW_LONGLONG),
14228 DEF_STATUS_VAR_FUNC("pending_compaction_limit_slowdowns",
14229 &io_stall_stats.slowdown_for_pending_compaction_bytes,
14230 SHOW_LONGLONG),
14231 DEF_STATUS_VAR_FUNC("memtable_limit_stops",
14232 &io_stall_stats.memtable_compaction, SHOW_LONGLONG),
14233 DEF_STATUS_VAR_FUNC("memtable_limit_slowdowns",
14234 &io_stall_stats.memtable_slowdown, SHOW_LONGLONG),
14235 DEF_STATUS_VAR_FUNC("total_stops", &io_stall_stats.total_stop,
14236 SHOW_LONGLONG),
14237 DEF_STATUS_VAR_FUNC("total_slowdowns", &io_stall_stats.total_slowdown,
14238 SHOW_LONGLONG),
14239 // end of the array marker
14240 {NullS, NullS, SHOW_LONG, SHOW_SCOPE_GLOBAL}};
14241
14242 11912 static void show_rocksdb_stall_vars(THD *thd, SHOW_VAR *var, char *buff) {
14243 11912 update_rocksdb_stall_status();
14244 11912 var->type = SHOW_ARRAY;
14245 11912 var->value = reinterpret_cast<char *>(&rocksdb_stall_status_variables);
14246 11912 }
14247
14248 static SHOW_VAR rocksdb_status_vars[] = {
14249 DEF_STATUS_VAR(block_cache_miss),
14250 DEF_STATUS_VAR(block_cache_hit),
14251 DEF_STATUS_VAR(block_cache_add),
14252 DEF_STATUS_VAR(block_cache_add_failures),
14253 DEF_STATUS_VAR(block_cache_index_miss),
14254 DEF_STATUS_VAR(block_cache_index_hit),
14255 DEF_STATUS_VAR(block_cache_index_add),
14256 DEF_STATUS_VAR(block_cache_index_bytes_insert),
14257 DEF_STATUS_VAR(block_cache_index_bytes_evict),
14258 DEF_STATUS_VAR(block_cache_filter_miss),
14259 DEF_STATUS_VAR(block_cache_filter_hit),
14260 DEF_STATUS_VAR(block_cache_filter_add),
14261 DEF_STATUS_VAR(block_cache_filter_bytes_insert),
14262 DEF_STATUS_VAR(block_cache_filter_bytes_evict),
14263 DEF_STATUS_VAR(block_cache_bytes_read),
14264 DEF_STATUS_VAR(block_cache_bytes_write),
14265 DEF_STATUS_VAR(block_cache_data_bytes_insert),
14266 DEF_STATUS_VAR(block_cache_data_miss),
14267 DEF_STATUS_VAR(block_cache_data_hit),
14268 DEF_STATUS_VAR(block_cache_data_add),
14269 DEF_STATUS_VAR(bloom_filter_useful),
14270 DEF_STATUS_VAR(bloom_filter_full_positive),
14271 DEF_STATUS_VAR(bloom_filter_full_true_positive),
14272 DEF_STATUS_VAR(memtable_hit),
14273 DEF_STATUS_VAR(memtable_miss),
14274 DEF_STATUS_VAR(get_hit_l0),
14275 DEF_STATUS_VAR(get_hit_l1),
14276 DEF_STATUS_VAR(get_hit_l2_and_up),
14277 DEF_STATUS_VAR(compaction_key_drop_new),
14278 DEF_STATUS_VAR(compaction_key_drop_obsolete),
14279 DEF_STATUS_VAR(compaction_key_drop_user),
14280 DEF_STATUS_VAR(number_keys_written),
14281 DEF_STATUS_VAR(number_keys_read),
14282 DEF_STATUS_VAR(number_keys_updated),
14283 DEF_STATUS_VAR(bytes_written),
14284 DEF_STATUS_VAR(bytes_read),
14285 DEF_STATUS_VAR(number_db_seek),
14286 DEF_STATUS_VAR(number_db_seek_found),
14287 DEF_STATUS_VAR(number_db_next),
14288 DEF_STATUS_VAR(number_db_next_found),
14289 DEF_STATUS_VAR(number_db_prev),
14290 DEF_STATUS_VAR(number_db_prev_found),
14291 DEF_STATUS_VAR(iter_bytes_read),
14292 DEF_STATUS_VAR(no_file_closes),
14293 DEF_STATUS_VAR(no_file_opens),
14294 DEF_STATUS_VAR(no_file_errors),
14295 DEF_STATUS_VAR(stall_micros),
14296 DEF_STATUS_VAR(num_iterators),
14297 DEF_STATUS_VAR(number_multiget_get),
14298 DEF_STATUS_VAR(number_multiget_keys_read),
14299 DEF_STATUS_VAR(number_multiget_bytes_read),
14300 DEF_STATUS_VAR(number_deletes_filtered),
14301 DEF_STATUS_VAR(number_merge_failures),
14302 DEF_STATUS_VAR(bloom_filter_prefix_checked),
14303 DEF_STATUS_VAR(bloom_filter_prefix_useful),
14304 DEF_STATUS_VAR(number_reseeks_iteration),
14305 DEF_STATUS_VAR(get_updates_since_calls),
14306 DEF_STATUS_VAR(block_cache_compressed_miss),
14307 DEF_STATUS_VAR(block_cache_compressed_hit),
14308 DEF_STATUS_VAR(wal_synced),
14309 DEF_STATUS_VAR(wal_bytes),
14310 DEF_STATUS_VAR(write_self),
14311 DEF_STATUS_VAR(write_other),
14312 DEF_STATUS_VAR(write_timedout),
14313 DEF_STATUS_VAR(write_wal),
14314 DEF_STATUS_VAR(flush_write_bytes),
14315 DEF_STATUS_VAR(compact_read_bytes),
14316 DEF_STATUS_VAR(compact_write_bytes),
14317 DEF_STATUS_VAR(number_superversion_acquires),
14318 DEF_STATUS_VAR(number_superversion_releases),
14319 DEF_STATUS_VAR(number_superversion_cleanups),
14320 DEF_STATUS_VAR(number_block_not_compressed),
14321 DEF_STATUS_VAR_PTR("row_lock_deadlocks", &rocksdb_row_lock_deadlocks,
14322 SHOW_LONGLONG),
14323 DEF_STATUS_VAR_PTR("row_lock_wait_timeouts",
14324 &rocksdb_row_lock_wait_timeouts, SHOW_LONGLONG),
14325 DEF_STATUS_VAR_PTR("snapshot_conflict_errors",
14326 &rocksdb_snapshot_conflict_errors, SHOW_LONGLONG),
14327 DEF_STATUS_VAR_PTR("wal_group_syncs", &rocksdb_wal_group_syncs,
14328 SHOW_LONGLONG),
14329 DEF_STATUS_VAR_PTR("manual_compactions_processed",
14330 &rocksdb_manual_compactions_processed, SHOW_LONGLONG),
14331 DEF_STATUS_VAR_PTR("manual_compactions_cancelled",
14332 &rocksdb_manual_compactions_cancelled, SHOW_LONGLONG),
14333 DEF_STATUS_VAR_PTR("manual_compactions_running",
14334 &rocksdb_manual_compactions_running, SHOW_LONGLONG),
14335 DEF_STATUS_VAR_PTR("manual_compactions_pending",
14336 &rocksdb_manual_compactions_pending, SHOW_LONGLONG),
14337 DEF_STATUS_VAR_PTR("number_sst_entry_put", &rocksdb_num_sst_entry_put,
14338 SHOW_LONGLONG),
14339 DEF_STATUS_VAR_PTR("number_sst_entry_delete", &rocksdb_num_sst_entry_delete,
14340 SHOW_LONGLONG),
14341 DEF_STATUS_VAR_PTR("number_sst_entry_singledelete",
14342 &rocksdb_num_sst_entry_singledelete, SHOW_LONGLONG),
14343 DEF_STATUS_VAR_PTR("number_sst_entry_merge", &rocksdb_num_sst_entry_merge,
14344 SHOW_LONGLONG),
14345 DEF_STATUS_VAR_PTR("number_sst_entry_other", &rocksdb_num_sst_entry_other,
14346 SHOW_LONGLONG),
14347 DEF_STATUS_VAR_PTR("additional_compaction_triggers",
14348 &rocksdb_additional_compaction_triggers, SHOW_LONGLONG),
14349 #ifndef NDEBUG
14350 DEF_STATUS_VAR_PTR("num_get_for_update_calls",
14351 &rocksdb_num_get_for_update_calls, SHOW_LONGLONG),
14352 #endif
14353 DEF_STATUS_VAR_PTR("partial_index_groups_sorted",
14354 &rocksdb_partial_index_groups_sorted, SHOW_LONGLONG),
14355 DEF_STATUS_VAR_PTR("partial_index_groups_materialized",
14356 &rocksdb_partial_index_groups_materialized,
14357 SHOW_LONGLONG),
14358 DEF_STATUS_VAR_PTR("partial_index_rows_sorted",
14359 &rocksdb_partial_index_rows_sorted, SHOW_LONGLONG),
14360 DEF_STATUS_VAR_PTR("partial_index_rows_materialized",
14361 &rocksdb_partial_index_rows_materialized, SHOW_LONGLONG),
14362
14363 // the variables generated by SHOW_FUNC are sorted only by prefix (first
14364 // arg in the tuple below), so make sure it is unique to make sorting
14365 // deterministic as quick sort is not stable
14366 {"rocksdb", reinterpret_cast<char *>(&show_myrocks_vars), SHOW_FUNC,
14367 SHOW_SCOPE_GLOBAL},
14368 {"rocksdb_stall", reinterpret_cast<char *>(&show_rocksdb_stall_vars),
14369 SHOW_FUNC, SHOW_SCOPE_GLOBAL},
14370 {NullS, NullS, SHOW_LONG, SHOW_SCOPE_GLOBAL}};
14371
14372 /*
14373 Background thread's main logic
14374 */
14375
14376 902 void Rdb_background_thread::run() {
14377 // How many seconds to wait till flushing the WAL next time.
14378 902 const int WAKE_UP_INTERVAL = 1;
14379
14380 timespec ts_next_sync;
14381 902 clock_gettime(CLOCK_REALTIME, &ts_next_sync);
14382 902 ts_next_sync.tv_sec += WAKE_UP_INTERVAL;
14383
14384 for (;;) {
14385 // Wait until the next timeout or until we receive a signal to stop the
14386 // thread. Request to stop the thread should only be triggered when the
14387 // storage engine is being unloaded.
14388
2/4
✓ Branch 0 taken 184349 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 184349 times.
✗ Branch 3 not taken.
184349 RDB_MUTEX_LOCK_CHECK(m_signal_mutex);
14389 const auto ret MY_ATTRIBUTE((__unused__)) =
14390
1/2
✓ Branch 0 taken 184313 times.
✗ Branch 1 not taken.
184349 mysql_cond_timedwait(&m_signal_cond, &m_signal_mutex, &ts_next_sync);
14391
14392 // Check that we receive only the expected error codes.
14393
3/4
✓ Branch 0 taken 183447 times.
✓ Branch 1 taken 866 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 183447 times.
184313 assert(ret == 0 || ret == ETIMEDOUT);
14394 184313 const std::atomic<THD::killed_state> local_killed(m_killed.load());
14395 184313 const bool local_save_stats = m_save_stats;
14396 184313 reset();
14397
2/4
✓ Branch 0 taken 184313 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 184313 times.
✗ Branch 3 not taken.
184313 RDB_MUTEX_UNLOCK_CHECK(m_signal_mutex);
14398
14399
2/2
✓ Branch 0 taken 866 times.
✓ Branch 1 taken 183447 times.
184313 if (local_killed) {
14400 // If we're here then that's because condition variable was signaled by
14401 // another thread and we're shutting down. Break out the loop to make
14402 // sure that shutdown thread can proceed.
14403 866 break;
14404 }
14405
14406 // This path should be taken only when the timer expired.
14407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183447 times.
183447 assert(ret == ETIMEDOUT);
14408
14409
2/2
✓ Branch 0 taken 8791 times.
✓ Branch 1 taken 174656 times.
183447 if (local_save_stats) {
14410
1/2
✓ Branch 0 taken 8791 times.
✗ Branch 1 not taken.
8791 ddl_manager.persist_stats();
14411 }
14412
14413 timespec ts;
14414 183447 clock_gettime(CLOCK_REALTIME, &ts);
14415
14416 // Flush the WAL. Sync it for both background and never modes to copy
14417 // InnoDB's behavior. For mode never, the wal file isn't even written,
14418 // whereas background writes to the wal file, but issues the syncs in a
14419 // background thread.
14420
5/6
✓ Branch 0 taken 183447 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4877 times.
✓ Branch 3 taken 178570 times.
✓ Branch 4 taken 4877 times.
✓ Branch 5 taken 178570 times.
188324 if (rdb && (rocksdb_flush_log_at_trx_commit != FLUSH_LOG_SYNC) &&
14421
1/2
✓ Branch 0 taken 4877 times.
✗ Branch 1 not taken.
4877 !rocksdb_db_options->allow_mmap_writes) {
14422
1/2
✓ Branch 0 taken 4877 times.
✗ Branch 1 not taken.
4877 bool sync = rdb_sync_wal_supported();
14423
1/2
✓ Branch 0 taken 4877 times.
✗ Branch 1 not taken.
4877 const rocksdb::Status s = rdb->FlushWAL(sync);
14424
2/4
✓ Branch 0 taken 4877 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4877 times.
4877 if (!s.ok()) {
14425 rdb_handle_io_error(s, RDB_IO_ERROR_BG_THREAD);
14426 }
14427 4877 }
14428
14429 // Recalculate statistics for indexes only if
14430 // rocksdb_table_stats_use_table_scan is disabled.
14431 // Otherwise, Rdb_index_stats_thread will do the work
14432
3/4
✓ Branch 0 taken 182737 times.
✓ Branch 1 taken 710 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 182737 times.
183447 if (!rocksdb_table_stats_use_table_scan && rocksdb_stats_recalc_rate) {
14433 std::vector<std::string> to_recalc;
14434 if (rdb_tables_to_recalc.empty()) {
14435 struct Rdb_index_collector : public Rdb_tables_scanner {
14436 int add_table(Rdb_tbl_def *tdef) override {
14437 rdb_tables_to_recalc.push_back(tdef->full_tablename());
14438 return HA_EXIT_SUCCESS;
14439 }
14440 } collector;
14441 ddl_manager.scan_for_tables(&collector);
14442 }
14443
14444 while (to_recalc.size() < rocksdb_stats_recalc_rate &&
14445 !rdb_tables_to_recalc.empty()) {
14446 to_recalc.push_back(rdb_tables_to_recalc.back());
14447 rdb_tables_to_recalc.pop_back();
14448 }
14449
14450 for (const auto &tbl_name : to_recalc) {
14451 calculate_stats_for_table(tbl_name, SCAN_TYPE_NONE);
14452 }
14453 }
14454
14455 // Set the next timestamp for mysql_cond_timedwait() (which ends up calling
14456 // pthread_cond_timedwait()) to wait on.
14457 183447 ts_next_sync.tv_sec = ts.tv_sec + WAKE_UP_INTERVAL;
14458 183447 }
14459
14460 // save remaining stats which might've left unsaved
14461
1/2
✓ Branch 0 taken 866 times.
✗ Branch 1 not taken.
866 ddl_manager.persist_stats();
14462 866 }
14463
14464 902 void Rdb_index_stats_thread::run() {
14465 902 const int WAKE_UP_INTERVAL = 1;
14466 #ifdef TARGET_OS_LINUX
14467 902 RDB_MUTEX_LOCK_CHECK(m_is_mutex);
14468 902 m_tid_set = true;
14469 902 m_tid = syscall(SYS_gettid);
14470 902 RDB_MUTEX_UNLOCK_CHECK(m_is_mutex);
14471 #endif
14472
14473 902 renice(rocksdb_table_stats_background_thread_nice_value);
14474 for (;;) {
14475
2/4
✓ Branch 0 taken 1621 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1621 times.
✗ Branch 3 not taken.
1621 RDB_MUTEX_LOCK_CHECK(m_signal_mutex);
14476
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1621 times.
1621 if (m_killed) {
14477 RDB_MUTEX_UNLOCK_CHECK(m_signal_mutex);
14478 break;
14479 }
14480
14481 timespec ts;
14482 1621 clock_gettime(CLOCK_REALTIME, &ts);
14483
14484 // Wait for 24 hours if the table scan based index calculation
14485 // is off. When the switch is turned on and any request is added
14486 // to the recalc queue, this thread will be signaled.
14487 3242 ts.tv_sec +=
14488
2/2
✓ Branch 0 taken 728 times.
✓ Branch 1 taken 893 times.
1621 (rocksdb_table_stats_use_table_scan) ? WAKE_UP_INTERVAL : 24 * 60 * 60;
14489
14490 const auto ret MY_ATTRIBUTE((__unused__)) =
14491
1/2
✓ Branch 0 taken 1585 times.
✗ Branch 1 not taken.
1621 mysql_cond_timedwait(&m_signal_cond, &m_signal_mutex, &ts);
14492
14493
2/2
✓ Branch 0 taken 866 times.
✓ Branch 1 taken 719 times.
1585 if (m_killed) {
14494
2/4
✓ Branch 0 taken 866 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 866 times.
✗ Branch 3 not taken.
866 RDB_MUTEX_UNLOCK_CHECK(m_signal_mutex);
14495 866 break;
14496 }
14497
14498 // Make sure, no program error is returned
14499
3/4
✓ Branch 0 taken 685 times.
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 685 times.
719 assert(ret == 0 || ret == ETIMEDOUT);
14500
2/4
✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 719 times.
✗ Branch 3 not taken.
719 RDB_MUTEX_UNLOCK_CHECK(m_signal_mutex);
14501
14502 for (;;) {
14503
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 760 times.
760 if (!rocksdb_table_stats_use_table_scan) {
14504 // Clear the recalc queue
14505 clear_all_index_stats_requests();
14506 break;
14507 }
14508
14509 760 std::string tbl_name;
14510
3/4
✓ Branch 0 taken 760 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 645 times.
✓ Branch 3 taken 115 times.
760 if (!get_index_stats_request(&tbl_name)) {
14511 // No request in the recalc queue
14512 645 break;
14513 }
14514
14515 115 Rdb_table_stats tbl_stats;
14516
3/4
✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 111 times.
115 if (ddl_manager.find_table_stats(tbl_name, &tbl_stats) !=
14517 HA_EXIT_SUCCESS) {
14518 // The table has been dropped. Skip this table.
14519 4 continue;
14520 }
14521
14522 111 clock_gettime(CLOCK_REALTIME, &ts);
14523
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 37 times.
111 if (difftime(ts.tv_sec, tbl_stats.m_last_recalc) <
14524 RDB_MIN_RECALC_INTERVAL) {
14525 /* Stats were (re)calculated not long ago. To avoid
14526 too frequent stats updates we put back the table on
14527 the recalc queue and do nothing. */
14528
14529
1/2
✓ Branch 0 taken 74 times.
✗ Branch 1 not taken.
74 add_index_stats_request(tbl_name);
14530 74 break;
14531 }
14532
14533
11/20
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 31 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 6 times.
✓ Branch 16 taken 6 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 6 times.
✗ Branch 19 not taken.
37 DBUG_EXECUTE_IF("rocksdb_is_bg_thread", {
14534 if (tbl_name == "test.t") {
14535 THD *thd = new THD();
14536 thd->thread_stack = reinterpret_cast<char *>(&thd);
14537 thd->store_globals();
14538
14539 static constexpr char act[] =
14540 "now wait_for ready_to_calculate_index_stats";
14541 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
14542
14543 thd->restore_globals();
14544 delete thd;
14545 }
14546 });
14547
14548 int err =
14549
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 calculate_stats_for_table(tbl_name, SCAN_TYPE_FULL_TABLE, &m_killed);
14550
14551
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if (err != HA_EXIT_SUCCESS) {
14552 global_stats.table_index_stats_result[TABLE_INDEX_STATS_FAILURE].inc();
14553 break;
14554 }
14555
14556
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 global_stats.table_index_stats_result[TABLE_INDEX_STATS_SUCCESS].inc();
14557
14558
11/20
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 31 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 6 times.
✓ Branch 16 taken 6 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 6 times.
✗ Branch 19 not taken.
37 DBUG_EXECUTE_IF("rocksdb_is_bg_thread", {
14559 if (tbl_name == "test.t") {
14560 THD *thd = new THD();
14561 thd->thread_stack = reinterpret_cast<char *>(&thd);
14562 thd->store_globals();
14563
14564 static constexpr char act[] =
14565 "now signal index_stats_calculation_done";
14566 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
14567
14568 thd->restore_globals();
14569 delete thd;
14570 }
14571 });
14572
3/3
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 719 times.
✓ Branch 2 taken 4 times.
801 }
14573 719 }
14574
14575 866 RDB_MUTEX_LOCK_CHECK(m_is_mutex);
14576 866 m_tid_set = false;
14577 866 m_tid = 0;
14578 866 RDB_MUTEX_UNLOCK_CHECK(m_is_mutex);
14579 866 }
14580
14581 760 bool Rdb_index_stats_thread::get_index_stats_request(std::string *tbl_name) {
14582 760 RDB_MUTEX_LOCK_CHECK(m_is_mutex);
14583
2/2
✓ Branch 0 taken 645 times.
✓ Branch 1 taken 115 times.
760 if (m_requests.empty()) {
14584 645 RDB_MUTEX_UNLOCK_CHECK(m_is_mutex);
14585 645 return false;
14586 }
14587
14588 115 *tbl_name = m_requests[0];
14589 115 m_requests.pop_front();
14590
14591 115 auto count = m_tbl_names.erase(*tbl_name);
14592
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 115 times.
115 if (count != 1) {
14593 assert(0);
14594 }
14595
14596 115 RDB_MUTEX_UNLOCK_CHECK(m_is_mutex);
14597 115 return true;
14598 }
14599
14600 154 void Rdb_index_stats_thread::add_index_stats_request(
14601 const std::string &tbl_name) {
14602
2/4
✓ Branch 0 taken 154 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 154 times.
✗ Branch 3 not taken.
154 RDB_MUTEX_LOCK_CHECK(m_is_mutex);
14603
14604 /* Quit if already in the queue */
14605
1/2
✓ Branch 0 taken 154 times.
✗ Branch 1 not taken.
154 auto ret = m_tbl_names.insert(tbl_name);
14606
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 115 times.
154 if (!ret.second) {
14607
2/4
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
39 RDB_MUTEX_UNLOCK_CHECK(m_is_mutex);
14608 39 return;
14609 }
14610
14611
1/2
✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
115 m_requests.push_back(*ret.first);
14612
2/4
✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 115 times.
✗ Branch 3 not taken.
115 RDB_MUTEX_UNLOCK_CHECK(m_is_mutex);
14613
1/2
✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
115 signal();
14614 }
14615
14616 6 void Rdb_index_stats_thread::clear_all_index_stats_requests() {
14617 6 RDB_MUTEX_LOCK_CHECK(m_is_mutex);
14618 6 m_requests.clear();
14619 6 m_tbl_names.clear();
14620 6 RDB_MUTEX_UNLOCK_CHECK(m_is_mutex);
14621 6 }
14622
14623 904 int Rdb_index_stats_thread::renice(int nice_val) {
14624 904 RDB_MUTEX_LOCK_CHECK(m_is_mutex);
14625
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 904 times.
904 if (!m_tid_set) {
14626 RDB_MUTEX_UNLOCK_CHECK(m_is_mutex);
14627 return HA_EXIT_FAILURE;
14628 }
14629
14630 #ifdef TARGET_OS_LINUX
14631 904 int ret = setpriority(PRIO_PROCESS, m_tid, nice_val);
14632
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 904 times.
904 if (ret != 0) {
14633 LogPluginErrMsg(ERROR_LEVEL, 0,
14634 "Set index stats thread priority failed due to %s",
14635 strerror(errno));
14636 RDB_MUTEX_UNLOCK_CHECK(m_is_mutex);
14637 return HA_EXIT_FAILURE;
14638 }
14639 #endif
14640
14641 904 RDB_MUTEX_UNLOCK_CHECK(m_is_mutex);
14642 904 return HA_EXIT_SUCCESS;
14643 }
14644
14645 11912 size_t Rdb_index_stats_thread::get_request_queue_size() {
14646 11912 size_t len = 0;
14647 11912 RDB_MUTEX_LOCK_CHECK(m_is_mutex);
14648 11912 len = m_requests.size();
14649 11912 RDB_MUTEX_UNLOCK_CHECK(m_is_mutex);
14650
14651 11912 return len;
14652 }
14653
14654 /*
14655 A background thread to handle manual compactions,
14656 except for dropping indexes/tables. Every second, it checks
14657 pending manual compactions, and it calls CompactRange if there is.
14658 */
14659 902 void Rdb_manual_compaction_thread::run() {
14660 902 RDB_MUTEX_LOCK_CHECK(m_signal_mutex);
14661 for (;;) {
14662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183899 times.
183899 if (m_killed) {
14663 break;
14664 }
14665 timespec ts;
14666 183899 clock_gettime(CLOCK_REALTIME, &ts);
14667 183899 ts.tv_sec += 1;
14668
14669 const auto ret MY_ATTRIBUTE((__unused__)) =
14670
1/2
✓ Branch 0 taken 183863 times.
✗ Branch 1 not taken.
183899 mysql_cond_timedwait(&m_signal_cond, &m_signal_mutex, &ts);
14671
2/2
✓ Branch 0 taken 866 times.
✓ Branch 1 taken 182997 times.
183863 if (m_killed) {
14672 866 break;
14673 }
14674 // make sure, no program error is returned
14675
2/4
✓ Branch 0 taken 182997 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 182997 times.
182997 assert(ret == 0 || ret == ETIMEDOUT);
14676
2/4
✓ Branch 0 taken 182997 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 182997 times.
✗ Branch 3 not taken.
182997 RDB_MUTEX_UNLOCK_CHECK(m_signal_mutex);
14677
14678
2/4
✓ Branch 0 taken 182997 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 182997 times.
✗ Branch 3 not taken.
182997 RDB_MUTEX_LOCK_CHECK(m_mc_mutex);
14679 // Grab the first PENDING state item and proceed, if not empty.
14680
2/2
✓ Branch 0 taken 181552 times.
✓ Branch 1 taken 1445 times.
182997 if (m_requests.empty()) {
14681
2/4
✓ Branch 0 taken 181552 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 181552 times.
✗ Branch 3 not taken.
181552 RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex);
14682
2/4
✓ Branch 0 taken 181552 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 181552 times.
✗ Branch 3 not taken.
181552 RDB_MUTEX_LOCK_CHECK(m_signal_mutex);
14683 181799 continue;
14684 }
14685 1445 auto it = m_requests.begin();
14686 1445 auto pending_it = m_requests.end();
14687 // Remove all items with client_done. client_done means
14688 // caller no longer uses the mcr object so it is safe to erase.
14689 // Pick first PENDING state item
14690 1445 it = m_requests.begin();
14691
2/2
✓ Branch 0 taken 2411 times.
✓ Branch 1 taken 1445 times.
3856 while (it != m_requests.end()) {
14692
2/2
✓ Branch 0 taken 1207 times.
✓ Branch 1 taken 1204 times.
2411 if (it->second.client_done) {
14693 // If state is PENDING, decrement counter
14694
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1207 times.
1207 if (it->second.state == Manual_compaction_request::PENDING) {
14695 rocksdb_manual_compactions_pending--;
14696 }
14697
1/2
✓ Branch 0 taken 1207 times.
✗ Branch 1 not taken.
1207 m_requests.erase(it++);
14698
3/4
✓ Branch 0 taken 1204 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1198 times.
✓ Branch 3 taken 6 times.
2408 } else if (it->second.state == Manual_compaction_request::PENDING &&
14699
2/2
✓ Branch 0 taken 1198 times.
✓ Branch 1 taken 6 times.
2408 pending_it == m_requests.end()) {
14700 // found
14701 1198 pending_it = it;
14702 1198 it++;
14703 } else {
14704 6 it++;
14705 }
14706 }
14707
2/2
✓ Branch 0 taken 247 times.
✓ Branch 1 taken 1198 times.
1445 if (pending_it == m_requests.end()) {
14708
2/4
✓ Branch 0 taken 247 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 247 times.
✗ Branch 3 not taken.
247 RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex);
14709
2/4
✓ Branch 0 taken 247 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 247 times.
✗ Branch 3 not taken.
247 RDB_MUTEX_LOCK_CHECK(m_signal_mutex);
14710 247 continue;
14711 }
14712
14713 1198 Manual_compaction_request &mcr = pending_it->second;
14714
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1198 times.
1198 assert(mcr.cf);
14715
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1198 times.
1198 assert(mcr.state == Manual_compaction_request::PENDING);
14716 1198 mcr.state = Manual_compaction_request::RUNNING;
14717 1198 rocksdb_manual_compactions_running++;
14718 1198 rocksdb_manual_compactions_pending--;
14719
2/4
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1198 times.
✗ Branch 3 not taken.
1198 RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex);
14720
14721
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1198 times.
1198 assert(mcr.state == Manual_compaction_request::RUNNING);
14722 // NO_LINT_DEBUG
14723
10/20
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1198 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1198 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1198 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1198 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1198 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1198 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1198 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1198 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1198 times.
✗ Branch 19 not taken.
1198 LogPluginErrMsg(INFORMATION_LEVEL, 0,
14724 "Manual Compaction id %d cf %s started.", mcr.mc_id,
14725 mcr.cf->GetName().c_str());
14726
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1189 times.
1198 if (rocksdb_debug_manual_compaction_delay > 0) {
14727 // In Facebook MySQL 5.6.35, my_sleep breaks the sleep when the server
14728 // gets a shutdown signal and this code depended on that behavior.
14729 // In 5.7, for whatever reason, this is not the case. my_sleep will
14730 // continue to sleep until the sleep time has elapsed. For the purpose
14731 // of this variable and the accompanying test case, we need to break this
14732 // down into a loop that sleeps and checks to see if the thread was
14733 // signalled with the stop flag. It is ugly, but without having DBUG_SYNC
14734 // available in background threads, it is good enough for the test.
14735
2/2
✓ Branch 0 taken 243 times.
✓ Branch 1 taken 9 times.
252 for (uint32_t sleeps = 0; sleeps < rocksdb_debug_manual_compaction_delay;
14736 sleeps++) {
14737
2/4
✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 243 times.
✗ Branch 3 not taken.
243 RDB_MUTEX_LOCK_CHECK(m_signal_mutex);
14738 243 const bool local_stop = m_killed;
14739
2/4
✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 243 times.
✗ Branch 3 not taken.
243 RDB_MUTEX_UNLOCK_CHECK(m_signal_mutex);
14740
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 243 times.
243 if (local_stop) break;
14741
1/2
✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
243 my_sleep(1000000);
14742 }
14743 }
14744
14745
10/18
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1195 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
1198 DBUG_EXECUTE_IF("rocksdb_manual_compaction", {
14746 THD *thd = new THD();
14747 thd->thread_stack = reinterpret_cast<char *>(&(thd));
14748 thd->store_globals();
14749 static constexpr char act[] =
14750 "now signal ready_to_mark_cf_dropped_in_manual_compaction wait_for "
14751 "mark_cf_dropped_done_in_manual_compaction";
14752 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
14753 thd->restore_globals();
14754 delete thd;
14755 });
14756
14757 // CompactRange may take a very long time. On clean shutdown,
14758 // it is cancelled by CancelAllBackgroundWork, then status is
14759 // set to shutdownInProgress.
14760 const rocksdb::Status s =
14761
1/2
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
1198 rdb->CompactRange(mcr.option, mcr.cf.get(), mcr.start, mcr.limit);
14762
14763 1198 rocksdb_manual_compactions_running--;
14764
3/4
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1186 times.
✓ Branch 3 taken 12 times.
1198 if (s.ok()) {
14765 1186 rocksdb_manual_compactions_processed++;
14766 // NO_LINT_DEBUG
14767
10/20
✓ Branch 0 taken 1186 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1186 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1186 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1186 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1186 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1186 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1186 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1186 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1186 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1186 times.
✗ Branch 19 not taken.
1186 LogPluginErrMsg(INFORMATION_LEVEL, 0,
14768 "Manual Compaction id %d cf %s ended.", mcr.mc_id,
14769 mcr.cf->GetName().c_str());
14770
1/2
✓ Branch 0 taken 1186 times.
✗ Branch 1 not taken.
1186 set_state(&mcr, Manual_compaction_request::SUCCESS);
14771 } else {
14772
4/6
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 9 times.
12 if (!cf_manager.get_cf(mcr.cf->GetID())) {
14773 // NO_LINT_DEBUG
14774
10/20
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✗ Branch 19 not taken.
3 LogPluginErrMsg(INFORMATION_LEVEL, 0, "cf %s has been dropped",
14775 mcr.cf->GetName().c_str());
14776
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 set_state(&mcr, Manual_compaction_request::SUCCESS);
14777
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 } else if (s.IsIncomplete()) {
14778 // NO_LINT_DEBUG
14779
13/26
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 9 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 9 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 9 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 9 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 9 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 9 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 9 times.
✗ Branch 25 not taken.
9 LogPluginErrMsg(INFORMATION_LEVEL, 0,
14780 "Manual Compaction id %d cf %s cancelled. (%d:%d, %s)",
14781 mcr.mc_id, mcr.cf->GetName().c_str(), s.code(),
14782 s.subcode(), s.getState());
14783 // Cancelled
14784
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 set_state(&mcr, Manual_compaction_request::CANCEL);
14785 9 rocksdb_manual_compactions_cancelled++;
14786 } else {
14787 // NO_LINT_DEBUG
14788 LogPluginErrMsg(INFORMATION_LEVEL, 0,
14789 "Manual Compaction id %d cf %s aborted. (%d:%d, %s)",
14790 mcr.mc_id, mcr.cf->GetName().c_str(), s.code(),
14791 s.subcode(), s.getState());
14792 set_state(&mcr, Manual_compaction_request::FAILURE);
14793 if (!s.IsShutdownInProgress()) {
14794 rdb_handle_io_error(s, RDB_IO_ERROR_BG_THREAD);
14795 } else {
14796 assert(m_requests.size() == 1);
14797 }
14798 }
14799 }
14800
2/4
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1198 times.
✗ Branch 3 not taken.
1198 RDB_MUTEX_LOCK_CHECK(m_signal_mutex);
14801 184195 }
14802 866 clear_all_manual_compaction_requests();
14803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 866 times.
866 assert(m_requests.empty());
14804 866 RDB_MUTEX_UNLOCK_CHECK(m_signal_mutex);
14805 866 }
14806
14807 866 void Rdb_manual_compaction_thread::clear_all_manual_compaction_requests() {
14808 866 RDB_MUTEX_LOCK_CHECK(m_mc_mutex);
14809
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 866 times.
866 assert(rocksdb_manual_compactions_pending == 0);
14810 866 m_requests.clear();
14811 866 RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex);
14812 866 }
14813
14814 13 void Rdb_manual_compaction_thread::
14815 cancel_all_pending_manual_compaction_requests() {
14816
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 RDB_MUTEX_LOCK_CHECK(m_mc_mutex);
14817 13 auto it = m_requests.begin();
14818
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 13 times.
19 while (it != m_requests.end()) {
14819 6 Manual_compaction_request &mcr = it->second;
14820
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (mcr.state == Manual_compaction_request::PENDING) {
14821 3 mcr.state = Manual_compaction_request::CANCEL;
14822 3 rocksdb_manual_compactions_cancelled++;
14823 3 rocksdb_manual_compactions_pending--;
14824 }
14825 6 it++;
14826 }
14827
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 assert(rocksdb_manual_compactions_pending == 0);
14828
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex);
14829 13 }
14830
14831 /**
14832 * Requesting to cancel a Manual Compaction job with mc_id.
14833 * Only PENDING or RUNNING states need cancellation.
14834 * This function may take a while if state is RUNNING.
14835 * Returning true if hitting timeout and state is RUNNING.
14836 */
14837 12 bool Rdb_manual_compaction_thread::cancel_manual_compaction_request(
14838 const int mc_id, const int timeout_100ms) {
14839 12 Manual_compaction_request::mc_state state =
14840 Manual_compaction_request::PENDING;
14841
14842
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 RDB_MUTEX_LOCK_CHECK(m_mc_mutex);
14843
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 auto it = m_requests.find(mc_id);
14844
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (it != m_requests.end()) {
14845 12 Manual_compaction_request &mcr = it->second;
14846
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (mcr.state == Manual_compaction_request::PENDING) {
14847 6 mcr.state = Manual_compaction_request::CANCEL;
14848 6 rocksdb_manual_compactions_cancelled++;
14849 6 rocksdb_manual_compactions_pending--;
14850
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex);
14851 6 return false;
14852
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 } else if (mcr.state == Manual_compaction_request::RUNNING) {
14853 // explicitly requesting to cancel compaction (cancellation happens in
14854 // background may take time)
14855 6 mcr.option.canceled->store(true, std::memory_order_release);
14856 6 state = mcr.state;
14857 }
14858 }
14859
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex);
14860
14861 // Waiting to get manual compaction to get cancelled.
14862 // Even if returning timeouts to clients, manual compaction
14863 // is still running so further compactions can remain
14864 // in pending state until the compaction completes cancellation.
14865 6 uint64_t retry = timeout_100ms;
14866
4/4
✓ Branch 0 taken 1811 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1808 times.
✓ Branch 3 taken 3 times.
1814 while (retry > 0 && state == Manual_compaction_request::RUNNING) {
14867
1/2
✓ Branch 0 taken 1808 times.
✗ Branch 1 not taken.
1808 my_sleep(100000);
14868 1808 retry--;
14869
1/2
✓ Branch 0 taken 1808 times.
✗ Branch 1 not taken.
1808 state = manual_compaction_state(mc_id);
14870 }
14871
14872
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 return retry <= 0 && state == Manual_compaction_request::RUNNING;
14873 }
14874
14875 /**
14876 * This function is for clients to request for Manual Compaction.
14877 * This function adds mcr (Manual Compaction Request) in a queue
14878 * as PENDING state then returns. Worker Thread then later picks it up
14879 * and processes compaction.
14880 * Clients should call set_client_done() when the clients are done with
14881 * the status of the requests.
14882 */
14883 1213 int Rdb_manual_compaction_thread::request_manual_compaction(
14884 std::shared_ptr<rocksdb::ColumnFamilyHandle> cf, rocksdb::Slice *start,
14885 rocksdb::Slice *limit, const uint manual_compaction_threads,
14886 const rocksdb::BottommostLevelCompaction bottommost_level_compaction) {
14887 1213 int mc_id = -1;
14888
2/4
✓ Branch 0 taken 1213 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1213 times.
✗ Branch 3 not taken.
1213 RDB_MUTEX_LOCK_CHECK(m_mc_mutex);
14889
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1207 times.
1213 if (m_requests.size() >= rocksdb_max_manual_compactions) {
14890
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex);
14891 6 return mc_id;
14892 }
14893 1207 Manual_compaction_request mcr;
14894 1207 mc_id = mcr.mc_id = ++m_latest_mc_id;
14895 1207 mcr.state = Manual_compaction_request::PENDING;
14896 1207 mcr.cf = cf;
14897 1207 mcr.start = start;
14898 1207 mcr.limit = limit;
14899 1207 mcr.option = getCompactRangeOptions(manual_compaction_threads,
14900 bottommost_level_compaction);
14901 mcr.canceled =
14902
2/4
✓ Branch 0 taken 1207 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1207 times.
✗ Branch 3 not taken.
1207 std::shared_ptr<std::atomic<bool>>(new std::atomic<bool>(false));
14903 1207 mcr.option.canceled = mcr.canceled.get();
14904 1207 mcr.client_done = false;
14905 1207 rocksdb_manual_compactions_pending++;
14906
2/4
✓ Branch 0 taken 1207 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1207 times.
✗ Branch 3 not taken.
1207 m_requests.insert(std::make_pair(mcr.mc_id, mcr));
14907
2/4
✓ Branch 0 taken 1207 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1207 times.
✗ Branch 3 not taken.
1207 RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex);
14908 1207 return mc_id;
14909 1207 }
14910
14911 Rdb_manual_compaction_thread::Manual_compaction_request::mc_state
14912 14579 Rdb_manual_compaction_thread::manual_compaction_state(const int mc_id) {
14913 14579 Manual_compaction_request::mc_state state =
14914 Manual_compaction_request::SUCCESS;
14915
2/4
✓ Branch 0 taken 14581 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14581 times.
✗ Branch 3 not taken.
14579 RDB_MUTEX_LOCK_CHECK(m_mc_mutex);
14916
1/2
✓ Branch 0 taken 14581 times.
✗ Branch 1 not taken.
14581 auto it = m_requests.find(mc_id);
14917
1/2
✓ Branch 0 taken 14581 times.
✗ Branch 1 not taken.
14581 if (it != m_requests.end()) {
14918 14581 state = it->second.state;
14919 }
14920
2/4
✓ Branch 0 taken 14581 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14581 times.
✗ Branch 3 not taken.
14581 RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex);
14921 14581 return state;
14922 }
14923
14924 1198 void Rdb_manual_compaction_thread::set_state(
14925 Manual_compaction_request *mcr,
14926 const Manual_compaction_request::mc_state new_state) {
14927 1198 RDB_MUTEX_LOCK_CHECK(m_mc_mutex);
14928 1198 mcr->state = new_state;
14929 1198 RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex);
14930 1198 }
14931
14932 1207 bool Rdb_manual_compaction_thread::set_client_done(const int mc_id) {
14933 1207 bool rc = false;
14934
2/4
✓ Branch 0 taken 1207 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1207 times.
✗ Branch 3 not taken.
1207 RDB_MUTEX_LOCK_CHECK(m_mc_mutex);
14935
1/2
✓ Branch 0 taken 1207 times.
✗ Branch 1 not taken.
1207 auto it = m_requests.find(mc_id);
14936
1/2
✓ Branch 0 taken 1207 times.
✗ Branch 1 not taken.
1207 if (it != m_requests.end()) {
14937 1207 Manual_compaction_request &mcr = it->second;
14938 1207 mcr.client_done = true;
14939 1207 rc = true;
14940 }
14941
2/4
✓ Branch 0 taken 1207 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1207 times.
✗ Branch 3 not taken.
1207 RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex);
14942 1207 return rc;
14943 }
14944
14945 /**
14946 * Locking read + Not Found + Read Committed occurs if we accessed
14947 * a row by Seek, tried to lock it, failed, released and reacquired the
14948 * snapshot (because of READ COMMITTED mode) and the row was deleted by
14949 * someone else in the meantime.
14950 * If so, we either just skipping the row, or re-creating a snapshot
14951 * and seek again. In both cases, Read Committed constraint is not broken.
14952 */
14953 186340909 bool ha_rocksdb::should_skip_invalidated_record(const int rc) const {
14954
6/6
✓ Branch 0 taken 4067900 times.
✓ Branch 1 taken 182273009 times.
✓ Branch 2 taken 78 times.
✓ Branch 3 taken 4067822 times.
✓ Branch 4 taken 78 times.
✓ Branch 5 taken 186340831 times.
186340987 if ((m_lock_rows != RDB_LOCK_NONE && rc == HA_ERR_KEY_NOT_FOUND &&
14955
1/2
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
78 my_core::thd_tx_isolation(ha_thd()) == ISO_READ_COMMITTED)) {
14956 78 return true;
14957 }
14958 186340831 return false;
14959 }
14960
14961 614 bool ha_rocksdb::should_skip_locked_record(const int rc) const {
14962
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 569 times.
614 if (m_locked_row_action == THR_SKIP) {
14963 /*
14964 In the spirit of SKIP LOCKED, Deadlock and Busy are also skipped as the
14965 goal is to skip conflicting rows and only lock the rows that can be
14966 updated later
14967 */
14968 if (rc == HA_ERR_LOCK_WAIT_TIMEOUT || rc == HA_ERR_LOCK_DEADLOCK ||
14969 HA_ERR_ROCKSDB_STATUS_BUSY) {
14970 45 return true;
14971 }
14972 }
14973 569 return false;
14974 }
14975
14976 /**
14977 * Indicating snapshot needs to be re-created and retrying seek again,
14978 * instead of returning errors or empty set. This is normally applicable
14979 * when hitting kBusy when locking the first row of the transaction,
14980 * with Repeatable Read isolation level.
14981 */
14982 257396 bool ha_rocksdb::should_recreate_snapshot(const int rc,
14983 const bool is_new_snapshot) const {
14984
5/6
✓ Branch 0 taken 257396 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 257375 times.
✓ Branch 4 taken 21 times.
✓ Branch 5 taken 257375 times.
257417 if (should_skip_invalidated_record(rc) ||
14985
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 (rc == HA_ERR_ROCKSDB_STATUS_BUSY && is_new_snapshot)) {
14986 21 return true;
14987 }
14988 257375 return false;
14989 }
14990
14991 /**
14992 * If calling put/delete/singledelete without locking the row,
14993 * it is necessary to pass assume_tracked=false to RocksDB TX API.
14994 * Read Free Replication and Blind Deletes are the cases when
14995 * using TX API and skipping row locking.
14996 */
14997 7783884 bool ha_rocksdb::can_assume_tracked(THD *thd) {
14998
5/6
✓ Branch 0 taken 7898824 times.
✓ Branch 1 taken 2519 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7899509 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 7899509 times.
7783884 if (use_read_free_rpl() || (THDVAR(thd, blind_delete_primary_key))) {
14999 3 return false;
15000 }
15001 7899509 return true;
15002 }
15003
15004 282933 bool ha_rocksdb::check_bloom_and_set_bounds(
15005 THD *thd, const Rdb_key_def &kd, const rocksdb::Slice &eq_cond,
15006 size_t bound_len, uchar *const lower_bound, uchar *const upper_bound,
15007 rocksdb::Slice *lower_bound_slice, rocksdb::Slice *upper_bound_slice) {
15008 282933 bool can_use_bloom = can_use_bloom_filter(thd, kd, eq_cond);
15009
6/6
✓ Branch 0 taken 218901 times.
✓ Branch 1 taken 64032 times.
✓ Branch 2 taken 218892 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 218892 times.
✓ Branch 5 taken 64041 times.
282933 if (!can_use_bloom && (THDVAR(thd, enable_iterate_bounds))) {
15010 218892 setup_iterator_bounds(kd, eq_cond, bound_len, lower_bound, upper_bound,
15011 lower_bound_slice, upper_bound_slice);
15012 }
15013 282933 return can_use_bloom;
15014 }
15015
15016 /**
15017 Deciding if it is possible to use bloom filter or not.
15018
15019 @detail
15020 Even if bloom filter exists, it is not always possible
15021 to use bloom filter. If using bloom filter when you shouldn't,
15022 false negative may happen -- fewer rows than expected may be returned.
15023 It is users' responsibility to use bloom filter correctly.
15024
15025 If bloom filter does not exist, return value does not matter because
15026 RocksDB does not use bloom filter internally.
15027
15028 @param kd
15029 @param eq_cond Equal condition part of the key. This always includes
15030 system index id (4 bytes).
15031 */
15032 282933 bool ha_rocksdb::can_use_bloom_filter(THD *thd, const Rdb_key_def &kd,
15033 const rocksdb::Slice &eq_cond) {
15034 282933 bool can_use = false;
15035
15036
2/2
✓ Branch 0 taken 60606 times.
✓ Branch 1 taken 222327 times.
282933 if (THDVAR(thd, skip_bloom_filter_on_read)) {
15037 60606 return can_use;
15038 }
15039
15040 222327 const rocksdb::SliceTransform *prefix_extractor = kd.get_extractor();
15041
2/2
✓ Branch 0 taken 70215 times.
✓ Branch 1 taken 152112 times.
222327 if (prefix_extractor) {
15042 /*
15043 This is an optimized use case for CappedPrefixTransform.
15044 If eq_cond length >= prefix extractor length and if
15045 all keys are used for equal lookup, it is
15046 always possible to use bloom filter.
15047
15048 Prefix bloom filter can't be used on descending scan with
15049 prefix lookup (i.e. WHERE id1=1 ORDER BY id2 DESC), because of
15050 RocksDB's limitation. On ascending (or not sorting) scan,
15051 keys longer than the capped prefix length will be truncated down
15052 to the capped length and the resulting key is added to the bloom filter.
15053
15054 Keys shorter than the capped prefix length will be added to
15055 the bloom filter. When keys are looked up, key conditionals
15056 longer than the capped length can be used; key conditionals
15057 shorter require all parts of the key to be available
15058 for the short key match.
15059 */
15060
2/2
✓ Branch 0 taken 64032 times.
✓ Branch 1 taken 6183 times.
70215 if (prefix_extractor->SameResultWhenAppended(eq_cond)) {
15061 64032 can_use = true;
15062 } else {
15063 6183 can_use = false;
15064 }
15065 }
15066
15067 222327 return can_use;
15068 }
15069
15070 /* For modules that need access to the global data structures */
15071 32821 rocksdb::TransactionDB *rdb_get_rocksdb_db() { return rdb; }
15072
15073 4064 Rdb_cf_manager &rdb_get_cf_manager() { return cf_manager; }
15074
15075 31 const rocksdb::BlockBasedTableOptions &rdb_get_table_options() {
15076 31 return *rocksdb_tbl_options;
15077 }
15078
15079 39038 bool rdb_is_table_scan_index_stats_calculation_enabled() {
15080 39038 return rocksdb_table_stats_use_table_scan;
15081 }
15082 59325 bool rdb_is_ttl_enabled() { return rocksdb_enable_ttl; }
15083 3987 bool rdb_is_ttl_read_filtering_enabled() {
15084 3987 return rocksdb_enable_ttl_read_filtering;
15085 }
15086 #if !defined(NDEBUG)
15087 2298 int rdb_dbug_set_ttl_rec_ts() { return rocksdb_debug_ttl_rec_ts; }
15088 1005 int rdb_dbug_set_ttl_snapshot_ts() { return rocksdb_debug_ttl_snapshot_ts; }
15089 1281 int rdb_dbug_set_ttl_read_filter_ts() {
15090 1281 return rocksdb_debug_ttl_read_filter_ts;
15091 }
15092 56429 bool rdb_dbug_set_ttl_ignore_pk() { return rocksdb_debug_ttl_ignore_pk; }
15093 #endif // !defined(NDEBUG)
15094
15095 16069 void rdb_update_global_stats(const operation_type &type, uint count,
15096 Rdb_tbl_def *td) {
15097
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16069 times.
16069 assert(type < ROWS_MAX);
15098
15099
2/2
✓ Branch 0 taken 14545 times.
✓ Branch 1 taken 1524 times.
16069 if (count == 0) {
15100 14545 return;
15101 }
15102
15103
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1524 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1524 if (td && td->m_is_mysql_system_table) {
15104 global_stats.system_rows[type].add(count);
15105 } else {
15106 1524 global_stats.rows[type].add(count);
15107 }
15108 }
15109
15110 54 int rdb_get_table_perf_counters(const char *const tablename,
15111 Rdb_perf_counters *const counters) {
15112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 assert(counters != nullptr);
15113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 assert(tablename != nullptr);
15114
15115 Rdb_table_handler *table_handler;
15116 54 table_handler = rdb_open_tables.get_table_handler(tablename);
15117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (table_handler == nullptr) {
15118 return HA_ERR_ROCKSDB_INVALID_TABLE;
15119 }
15120
15121 54 counters->load(table_handler->m_table_perf_context);
15122
15123 54 rdb_open_tables.release_table_handler(table_handler);
15124 54 return HA_EXIT_SUCCESS;
15125 }
15126
15127 const char *get_rdb_io_error_string(const RDB_IO_ERROR_TYPE err_type) {
15128 // If this assertion fails then this means that a member has been either added
15129 // to or removed from RDB_IO_ERROR_TYPE enum and this function needs to be
15130 // changed to return the appropriate value.
15131 static_assert(RDB_IO_ERROR_LAST == 4, "Please handle all the error types.");
15132
15133 switch (err_type) {
15134 case RDB_IO_ERROR_TYPE::RDB_IO_ERROR_TX_COMMIT:
15135 return "RDB_IO_ERROR_TX_COMMIT";
15136 case RDB_IO_ERROR_TYPE::RDB_IO_ERROR_DICT_COMMIT:
15137 return "RDB_IO_ERROR_DICT_COMMIT";
15138 case RDB_IO_ERROR_TYPE::RDB_IO_ERROR_BG_THREAD:
15139 return "RDB_IO_ERROR_BG_THREAD";
15140 case RDB_IO_ERROR_TYPE::RDB_IO_ERROR_GENERAL:
15141 return "RDB_IO_ERROR_GENERAL";
15142 default:
15143 assert(false);
15144 return "(unknown)";
15145 }
15146 }
15147
15148 // In case of core dump generation we want this function NOT to be optimized
15149 // so that we can capture as much data as possible to debug the root cause
15150 // more efficiently.
15151 #if defined(NDEBUG)
15152 #ifdef __clang__
15153 MY_ATTRIBUTE((optnone))
15154 #else
15155 MY_ATTRIBUTE((optimize("O0")))
15156 #endif
15157 #endif
15158 void rdb_handle_io_error(const rocksdb::Status status,
15159 const RDB_IO_ERROR_TYPE err_type) {
15160 if (status.IsIOError()) {
15161 switch (err_type) {
15162 case RDB_IO_ERROR_TX_COMMIT:
15163 case RDB_IO_ERROR_DICT_COMMIT: {
15164 rdb_log_status_error(status, "failed to write to WAL");
15165 LogPluginErrMsg(ERROR_LEVEL, 0, "aborting on WAL write error.");
15166 abort();
15167 break;
15168 }
15169 case RDB_IO_ERROR_BG_THREAD: {
15170 rdb_log_status_error(status, "BG thread failed to write to RocksDB");
15171 /* NO_LINT_DEBUG */
15172 LogPluginErrMsg(ERROR_LEVEL, 0, "aborting on BG write error.");
15173 abort();
15174 break;
15175 }
15176 case RDB_IO_ERROR_GENERAL: {
15177 rdb_log_status_error(status, "failed on I/O");
15178 LogPluginErrMsg(ERROR_LEVEL, 0, "aborting on I/O error.");
15179 abort();
15180 break;
15181 }
15182 default:
15183 assert(0);
15184 break;
15185 }
15186 } else if (status.IsCorruption()) {
15187 rdb_log_status_error(status, "data corruption detected!");
15188 rdb_persist_corruption_marker();
15189 LogPluginErrMsg(ERROR_LEVEL, 0, "aborting because of data corruption.");
15190 abort();
15191 } else if (!status.ok()) {
15192 switch (err_type) {
15193 case RDB_IO_ERROR_TX_COMMIT:
15194 case RDB_IO_ERROR_DICT_COMMIT: {
15195 rdb_log_status_error(status, "Failed to write to WAL (non kIOError)");
15196 LogPluginErrMsg(ERROR_LEVEL, 0, "aborting on WAL write error.");
15197 abort();
15198 break;
15199 }
15200 default:
15201 rdb_log_status_error(status, "Failed to read/write in RocksDB");
15202 break;
15203 }
15204 }
15205 }
15206
15207 201034 Rdb_dict_manager_selector *rdb_get_dict_manager(void) { return &dict_manager; }
15208
15209 22451 Rdb_ddl_manager *rdb_get_ddl_manager(void) { return &ddl_manager; }
15210
15211 11390 Rdb_hton_init_state *rdb_get_hton_init_state(void) { return &hton_init_state; }
15212
15213 1089 void rocksdb_set_compaction_options(
15214 my_core::THD *const thd MY_ATTRIBUTE((__unused__)),
15215 my_core::SYS_VAR *const var MY_ATTRIBUTE((__unused__)), void *const var_ptr,
15216 const void *const save) {
15217
3/4
✓ Branch 0 taken 163 times.
✓ Branch 1 taken 926 times.
✓ Branch 2 taken 163 times.
✗ Branch 3 not taken.
1089 if (var_ptr && save) {
15218 163 *(uint64_t *)var_ptr = *(const uint64_t *)save;
15219 }
15220 const Rdb_compact_params params = {
15221 1089 (uint64_t)rocksdb_compaction_sequential_deletes,
15222 1089 (uint64_t)rocksdb_compaction_sequential_deletes_window,
15223 1089 (uint64_t)rocksdb_compaction_sequential_deletes_file_size};
15224
1/2
✓ Branch 0 taken 1089 times.
✗ Branch 1 not taken.
1089 if (properties_collector_factory) {
15225 1089 properties_collector_factory->SetCompactionParams(params);
15226 }
15227 1089 }
15228
15229 22 void rocksdb_set_table_stats_sampling_pct(
15230 my_core::THD *const thd MY_ATTRIBUTE((__unused__)),
15231 my_core::SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
15232 void *const var_ptr MY_ATTRIBUTE((__unused__)), const void *const save) {
15233 22 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
15234
15235 22 const uint32_t new_val = *static_cast<const uint32_t *>(save);
15236
15237
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
22 if (new_val != rocksdb_table_stats_sampling_pct) {
15238 18 rocksdb_table_stats_sampling_pct = new_val;
15239
15240
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (properties_collector_factory) {
15241 18 properties_collector_factory->SetTableStatsSamplingPct(
15242 rocksdb_table_stats_sampling_pct);
15243 }
15244 }
15245
15246 22 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
15247 22 }
15248
15249 22 void rocksdb_update_table_stats_use_table_scan(THD *const /* thd */,
15250 struct SYS_VAR *const /* var */,
15251 void *const var_ptr,
15252 const void *const save) {
15253 22 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
15254 22 bool old_val = *static_cast<const bool *>(var_ptr);
15255 22 bool new_val = *static_cast<const bool *>(save);
15256
15257
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 12 times.
22 if (old_val == new_val) {
15258 10 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
15259 10 return;
15260 }
15261
15262
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (new_val) {
15263 struct Rdb_table_collector : public Rdb_tables_scanner {
15264 3 int add_table(Rdb_tbl_def *tdef) override {
15265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 assert(tdef->m_key_count > 0);
15266
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 tdef->m_tbl_stats.set(tdef->m_key_count > 0
15267 3 ? tdef->m_key_descr_arr[0]->m_stats.m_rows
15268 : 0,
15269 0, 0);
15270 3 return HA_EXIT_SUCCESS;
15271 }
15272 6 } collector;
15273
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 ddl_manager.scan_for_tables(&collector);
15274
15275 // We do not add all tables to the index stats recalculation queue
15276 // to avoid index stats calculation workload spike.
15277 } else {
15278 6 rdb_is_thread.clear_all_index_stats_requests();
15279 }
15280
15281 12 *static_cast<bool *>(var_ptr) = *static_cast<const bool *>(save);
15282 12 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
15283 }
15284
15285 2 int rocksdb_index_stats_thread_renice(THD *const /* thd */,
15286 struct SYS_VAR *const /* var */,
15287 void *const save,
15288 struct st_mysql_value *const value) {
15289 long long nice_val;
15290 /* value is NULL */
15291
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (value->val_int(value, &nice_val)) {
15292 return HA_EXIT_FAILURE;
15293 }
15294
15295
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (rdb_is_thread.renice(nice_val) != HA_EXIT_SUCCESS) {
15296 return HA_EXIT_FAILURE;
15297 }
15298
15299 2 *static_cast<int32_t *>(save) = static_cast<int32_t>(nice_val);
15300 2 return HA_EXIT_SUCCESS;
15301 }
15302
15303 /*
15304 This function allows setting the rate limiter's bytes per second value
15305 but only if the rate limiter is turned on which has to be done at startup.
15306 If the rate is already 0 (turned off) or we are changing it to 0 (trying
15307 to turn it off) this function will push a warning to the client and do
15308 nothing.
15309 This is similar to the code in innodb_doublewrite_update (found in
15310 storage/innobase/handler/ha_innodb.cc).
15311 */
15312 14 void rocksdb_set_rate_limiter_bytes_per_sec(
15313 my_core::THD *const thd,
15314 my_core::SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
15315 void *const var_ptr MY_ATTRIBUTE((__unused__)), const void *const save) {
15316 14 const uint64_t new_val = *static_cast<const uint64_t *>(save);
15317
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 6 times.
14 if (new_val == 0 || rocksdb_rate_limiter_bytes_per_sec == 0) {
15318 /*
15319 If a rate_limiter was not enabled at startup we can't change it nor
15320 can we disable it if one was created at startup
15321 */
15322 8 push_warning_printf(thd, Sql_condition::SL_WARNING, ER_WRONG_ARGUMENTS,
15323 "RocksDB: rocksdb_rate_limiter_bytes_per_sec cannot "
15324 "be dynamically changed to or from 0. Do a clean "
15325 "shutdown if you want to change it from or to 0.");
15326
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 } else if (new_val != rocksdb_rate_limiter_bytes_per_sec) {
15327 /* Apply the new value to the rate limiter and store it locally */
15328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 assert(rocksdb_rate_limiter != nullptr);
15329 6 rocksdb_rate_limiter_bytes_per_sec = new_val;
15330 6 rocksdb_rate_limiter->SetBytesPerSecond(new_val);
15331 }
15332 14 }
15333
15334 7 void rocksdb_set_sst_mgr_rate_bytes_per_sec(
15335 my_core::THD *const thd,
15336 my_core::SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
15337 void *const var_ptr MY_ATTRIBUTE((__unused__)), const void *const save) {
15338 7 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
15339
15340 7 const uint64_t new_val = *static_cast<const uint64_t *>(save);
15341
15342
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if (new_val != rocksdb_sst_mgr_rate_bytes_per_sec) {
15343 4 rocksdb_sst_mgr_rate_bytes_per_sec = new_val;
15344
15345 4 rocksdb_db_options->sst_file_manager->SetDeleteRateBytesPerSecond(
15346 rocksdb_sst_mgr_rate_bytes_per_sec);
15347 }
15348
15349 7 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
15350 7 }
15351
15352 7 void rocksdb_set_delayed_write_rate(THD *thd, struct SYS_VAR *var,
15353 void *var_ptr, const void *save) {
15354 7 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
15355 7 const uint64_t new_val = *static_cast<const uint64_t *>(save);
15356
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if (rocksdb_delayed_write_rate != new_val) {
15357 4 rocksdb_delayed_write_rate = new_val;
15358 rocksdb::Status s =
15359
4/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
16 rdb->SetDBOptions({{"delayed_write_rate", std::to_string(new_val)}});
15360
15361
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (!s.ok()) {
15362 LogPluginErrMsg(
15363 WARNING_LEVEL, 0,
15364 "failed to update delayed_write_rate. status code = %d, status = %s",
15365 s.code(), s.ToString().c_str());
15366 }
15367 4 }
15368 7 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
15369 7 }
15370
15371 38 void rocksdb_set_max_latest_deadlocks(THD *thd, struct SYS_VAR *var,
15372 void *var_ptr, const void *save) {
15373 38 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
15374 38 const uint32_t new_val = *static_cast<const uint32_t *>(save);
15375
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 1 times.
38 if (rocksdb_max_latest_deadlocks != new_val) {
15376 37 rocksdb_max_latest_deadlocks = new_val;
15377 37 rdb->SetDeadlockInfoBufferSize(rocksdb_max_latest_deadlocks);
15378 }
15379 38 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
15380 38 }
15381
15382 938 void rdb_set_collation_exception_list(const char *const exception_list) {
15383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 938 times.
938 assert(rdb_collation_exceptions != nullptr);
15384
15385
3/6
✓ Branch 0 taken 938 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 938 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 938 times.
938 if (!rdb_collation_exceptions->set_patterns(exception_list,
15386 get_regex_flags())) {
15387 warn_about_bad_patterns(rdb_collation_exceptions,
15388 "strict_collation_exceptions");
15389 }
15390 938 }
15391
15392 36 void rocksdb_set_collation_exception_list(THD *const thd,
15393 struct SYS_VAR *const var,
15394 void *const var_ptr,
15395 const void *const save) {
15396 36 const char *const val = *static_cast<const char *const *>(save);
15397
15398
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 rdb_set_collation_exception_list(val == nullptr ? "" : val);
15399
15400 36 *static_cast<const char **>(var_ptr) = val;
15401 36 }
15402
15403 1524 int mysql_value_to_bool(struct st_mysql_value *value, bool *return_value) {
15404 1524 int new_value_type = value->value_type(value);
15405
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 1486 times.
1524 if (new_value_type == MYSQL_VALUE_TYPE_STRING) {
15406 char buf[16];
15407 38 int len = sizeof(buf);
15408
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 const char *str = value->val_str(value, buf, &len);
15409
5/8
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 22 times.
✓ Branch 7 taken 16 times.
76 if (str && (my_strcasecmp(system_charset_info, "true", str) == 0 ||
15410
3/4
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 16 times.
38 my_strcasecmp(system_charset_info, "on", str) == 0)) {
15411 22 *return_value = true;
15412
5/8
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 9 times.
32 } else if (str && (my_strcasecmp(system_charset_info, "false", str) == 0 ||
15413
3/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 9 times.
16 my_strcasecmp(system_charset_info, "off", str) == 0)) {
15414 7 *return_value = false;
15415 } else {
15416 9 return 1;
15417 }
15418
1/2
✓ Branch 0 taken 1486 times.
✗ Branch 1 not taken.
1486 } else if (new_value_type == MYSQL_VALUE_TYPE_INT) {
15419 long long intbuf;
15420
1/2
✓ Branch 0 taken 1486 times.
✗ Branch 1 not taken.
1486 value->val_int(value, &intbuf);
15421
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1486 times.
1486 if (intbuf > 1) return 1;
15422 1486 *return_value = intbuf > 0;
15423 } else {
15424 return 1;
15425 }
15426
15427 1515 return 0;
15428 }
15429
15430 64 static int rocksdb_validate_flush_log_at_trx_commit(
15431 THD *const thd,
15432 struct SYS_VAR *const var, /* in: pointer to system variable */
15433 void *var_ptr, /* out: immediate result for update function */
15434 struct st_mysql_value *const value /* in: incoming value */) {
15435 long long new_value;
15436
15437 /* value is NULL */
15438
2/4
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
64 if (value->val_int(value, &new_value)) {
15439 return 1;
15440 }
15441
15442
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 64 times.
64 if (rocksdb_db_options->allow_mmap_writes && new_value != FLUSH_LOG_NEVER) {
15443 return 1;
15444 }
15445
15446
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 bool write_disable_wal = THDVAR(thd, write_disable_wal);
15447
4/4
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 26 times.
64 if (new_value == FLUSH_LOG_SYNC && write_disable_wal) {
15448
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_error(
15449 ER_GET_ERRMSG, MYF(0), HA_ERR_ROCKSDB_STATUS_INVALID_ARGUMENT,
15450 "rocksdb_flush_log_at_trx_commit = 1 and rocksdb_write_disable_wal = ON"
15451 " are not compatible",
15452 rocksdb_hton_name);
15453 1 return 1;
15454 }
15455
15456 63 *static_cast<uint32_t *>(var_ptr) = static_cast<uint32_t>(new_value);
15457 63 return HA_EXIT_SUCCESS;
15458 }
15459 124 static int rocksdb_check_write_disable_wal(
15460 THD *const thd, struct SYS_VAR *var MY_ATTRIBUTE((__unused__)), void *save,
15461 struct st_mysql_value *value) {
15462 bool new_value;
15463
3/4
✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 123 times.
124 if (mysql_value_to_bool(value, &new_value) != 0) {
15464 1 return 1;
15465 }
15466
15467
4/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 115 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 7 times.
123 if (rocksdb_flush_log_at_trx_commit == FLUSH_LOG_SYNC && new_value) {
15468
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_error(
15469 ER_GET_ERRMSG, MYF(0), HA_ERR_ROCKSDB_STATUS_INVALID_ARGUMENT,
15470 "rocksdb_flush_log_at_trx_commit = 1 and rocksdb_write_disable_wal = ON"
15471 " are not compatible",
15472 rocksdb_hton_name);
15473 1 return 1;
15474 }
15475
15476 122 *static_cast<bool *>(save) = new_value;
15477
15478
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 THDVAR(thd, write_disable_wal_save) = false;
15479 122 return 0;
15480 }
15481
15482 268 int rocksdb_check_bulk_load(THD *const thd,
15483 struct SYS_VAR *var MY_ATTRIBUTE((__unused__)),
15484 void *save, struct st_mysql_value *value) {
15485 bool new_value;
15486
3/4
✓ Branch 0 taken 268 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 264 times.
268 if (mysql_value_to_bool(value, &new_value) != 0) {
15487 4 return 1;
15488 }
15489
15490
1/2
✓ Branch 0 taken 264 times.
✗ Branch 1 not taken.
264 Rdb_transaction *tx = get_tx_from_thd(thd);
15491
2/2
✓ Branch 0 taken 194 times.
✓ Branch 1 taken 70 times.
264 if (tx != nullptr) {
15492 bool is_critical_error;
15493
1/2
✓ Branch 0 taken 194 times.
✗ Branch 1 not taken.
194 const int rc = tx->finish_bulk_load(&is_critical_error);
15494
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
194 if (rc != 0 && is_critical_error) {
15495
9/18
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LogPluginErrMsg(ERROR_LEVEL, 0,
15496 "Error %d finalizing last SST file while setting bulk "
15497 "loading variable",
15498 rc);
15499
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 THDVAR(thd, bulk_load) = 0;
15500 3 return 1;
15501 }
15502 }
15503
15504 261 *static_cast<bool *>(save) = new_value;
15505 261 return 0;
15506 }
15507
15508 62 int rocksdb_check_bulk_load_allow_unsorted(
15509 THD *const thd, struct SYS_VAR *var MY_ATTRIBUTE((__unused__)), void *save,
15510 struct st_mysql_value *value) {
15511 bool new_value;
15512
3/4
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 58 times.
62 if (mysql_value_to_bool(value, &new_value) != 0) {
15513 4 return 1;
15514 }
15515
15516
3/4
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 55 times.
58 if (THDVAR(thd, bulk_load)) {
15517
9/18
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LogPluginErrMsg(ERROR_LEVEL, 0,
15518 "Cannot change this setting while bulk load is enabled");
15519
15520 3 return 1;
15521 }
15522
15523 55 *static_cast<bool *>(save) = new_value;
15524 55 return 0;
15525 }
15526
15527 11 static void rocksdb_set_max_background_jobs(THD *thd, struct SYS_VAR *const var,
15528 void *const var_ptr,
15529 const void *const save) {
15530
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 assert(save != nullptr);
15531
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 assert(rocksdb_db_options != nullptr);
15532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 assert(rocksdb_db_options->env != nullptr);
15533
15534 11 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
15535
15536 11 const int new_val = *static_cast<const int *>(save);
15537
15538
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
11 if (rocksdb_db_options->max_background_jobs != new_val) {
15539 10 rocksdb_db_options->max_background_jobs = new_val;
15540 rocksdb::Status s =
15541
4/8
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
40 rdb->SetDBOptions({{"max_background_jobs", std::to_string(new_val)}});
15542
15543
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (!s.ok()) {
15544 LogPluginErrMsg(WARNING_LEVEL, 0,
15545 "failed to update max_background_jobs. Status code = %d, "
15546 "status = %s.",
15547 s.code(), s.ToString().c_str());
15548 }
15549 10 }
15550
15551 11 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
15552 11 }
15553
15554 5 static void rocksdb_set_max_background_compactions(THD *thd,
15555 struct SYS_VAR *const var,
15556 void *const var_ptr,
15557 const void *const save) {
15558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 assert(save != nullptr);
15559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 assert(rocksdb_db_options != nullptr);
15560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 assert(rocksdb_db_options->env != nullptr);
15561
15562 5 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
15563
15564 5 const int new_val = *static_cast<const int *>(save);
15565
15566
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (rocksdb_db_options->max_background_compactions != new_val) {
15567 4 rocksdb_db_options->max_background_compactions = new_val;
15568 4 rocksdb::Status s = rdb->SetDBOptions(
15569
4/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
12 {{"max_background_compactions", std::to_string(new_val)}});
15570
15571
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (!s.ok()) {
15572 /* NO_LINT_DEBUG */
15573 LogPluginErrMsg(WARNING_LEVEL, 0,
15574 "MyRocks: failed to update max_background_compactions. "
15575 "Status code = %d, status = %s.",
15576 s.code(), s.ToString().c_str());
15577 }
15578 4 }
15579
15580 5 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
15581 5 }
15582
15583 /**
15584 rocksdb_set_max_bottom_pri_background_compactions_internal() changes
15585 the number of rocksdb background threads.
15586 Creating new threads may take up to a few seconds, so instead of
15587 calling the function at sys_var::update path where global mutex is held,
15588 doing at sys_var::check path so that other queries are not blocked.
15589 Same optimization is done for rocksdb_block_cache_size too.
15590 */
15591 15 static int rocksdb_validate_max_bottom_pri_background_compactions(
15592 THD *thd MY_ATTRIBUTE((__unused__)),
15593 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)), void *var_ptr,
15594 struct st_mysql_value *value) {
15595
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 assert(value != nullptr);
15596
15597 long long new_value;
15598
15599 /* value is NULL */
15600
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
15 if (value->val_int(value, &new_value)) {
15601 return HA_EXIT_FAILURE;
15602 }
15603
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (new_value < 0 ||
15604
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 new_value > ROCKSDB_MAX_BOTTOM_PRI_BACKGROUND_COMPACTIONS) {
15605 return HA_EXIT_FAILURE;
15606 }
15607
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 RDB_MUTEX_LOCK_CHECK(rdb_bottom_pri_background_compactions_resize_mutex);
15608
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 1 times.
15 if (rocksdb_max_bottom_pri_background_compactions != new_value) {
15609
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
14 if (new_value == 0) {
15610
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), "SET",
15611 "max_bottom_pri_background_compactions can't be changed to 0 "
15612 "online.");
15613
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 RDB_MUTEX_UNLOCK_CHECK(
15614 rdb_bottom_pri_background_compactions_resize_mutex);
15615 3 return HA_EXIT_FAILURE;
15616 }
15617
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 rocksdb_set_max_bottom_pri_background_compactions_internal(new_value);
15618 }
15619 12 *static_cast<int64_t *>(var_ptr) = static_cast<int64_t>(new_value);
15620
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 RDB_MUTEX_UNLOCK_CHECK(rdb_bottom_pri_background_compactions_resize_mutex);
15621 12 return HA_EXIT_SUCCESS;
15622 }
15623
15624 7 static void rocksdb_set_bytes_per_sync(
15625 THD *thd MY_ATTRIBUTE((__unused__)),
15626 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
15627 void *const var_ptr MY_ATTRIBUTE((__unused__)), const void *const save) {
15628
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(save != nullptr);
15629
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(rocksdb_db_options != nullptr);
15630
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(rocksdb_db_options->env != nullptr);
15631
15632 7 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
15633
15634 7 const ulonglong new_val = *static_cast<const ulonglong *>(save);
15635
15636
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if (rocksdb_db_options->bytes_per_sync != new_val) {
15637 4 rocksdb_db_options->bytes_per_sync = new_val;
15638 rocksdb::Status s =
15639
4/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
16 rdb->SetDBOptions({{"bytes_per_sync", std::to_string(new_val)}});
15640
15641
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (!s.ok()) {
15642 LogPluginErrMsg(WARNING_LEVEL, 0,
15643 "failed to update max_background_jobs. Status code = %d, "
15644 "status = %s.",
15645 s.code(), s.ToString().c_str());
15646 }
15647 4 }
15648
15649 7 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
15650 7 }
15651
15652 7 static void rocksdb_set_wal_bytes_per_sync(
15653 THD *thd MY_ATTRIBUTE((__unused__)),
15654 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)),
15655 void *const var_ptr MY_ATTRIBUTE((__unused__)), const void *const save) {
15656
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(save != nullptr);
15657
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(rocksdb_db_options != nullptr);
15658
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(rocksdb_db_options->env != nullptr);
15659
15660 7 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
15661
15662 7 const ulonglong new_val = *static_cast<const ulonglong *>(save);
15663
15664
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if (rocksdb_db_options->wal_bytes_per_sync != new_val) {
15665 4 rocksdb_db_options->wal_bytes_per_sync = new_val;
15666 rocksdb::Status s =
15667
4/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
16 rdb->SetDBOptions({{"wal_bytes_per_sync", std::to_string(new_val)}});
15668
15669
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (!s.ok()) {
15670 LogPluginErrMsg(WARNING_LEVEL, 0,
15671 "failed to update max_background_jobs. Status code = %d, "
15672 "status = %s.",
15673 s.code(), s.ToString().c_str());
15674 }
15675 4 }
15676
15677 7 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
15678 7 }
15679
15680 /*
15681 Validating and updating block cache size via sys_var::check path.
15682 SetCapacity may take seconds when reducing block cache, and
15683 sys_var::update holds LOCK_global_system_variables mutex, so
15684 updating block cache size is done at check path instead.
15685 */
15686 10 static int rocksdb_validate_set_block_cache_size(
15687 THD *thd MY_ATTRIBUTE((__unused__)),
15688 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)), void *var_ptr,
15689 struct st_mysql_value *value) {
15690
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 assert(value != nullptr);
15691
15692 long long new_value;
15693
15694 /* value is NULL */
15695
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (value->val_int(value, &new_value)) {
15696 return HA_EXIT_FAILURE;
15697 }
15698
15699
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (new_value < RDB_MIN_BLOCK_CACHE_SIZE ||
15700
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 (uint64_t)new_value > (uint64_t)LLONG_MAX) {
15701 return HA_EXIT_FAILURE;
15702 }
15703
15704
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 RDB_MUTEX_LOCK_CHECK(rdb_block_cache_resize_mutex);
15705 const rocksdb::BlockBasedTableOptions &table_options =
15706
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 rdb_get_table_options();
15707
15708
5/6
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 1 times.
10 if (rocksdb_block_cache_size != new_value && table_options.block_cache) {
15709
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 table_options.block_cache->SetCapacity(new_value);
15710 }
15711 10 *static_cast<int64_t *>(var_ptr) = static_cast<int64_t>(new_value);
15712
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 RDB_MUTEX_UNLOCK_CHECK(rdb_block_cache_resize_mutex);
15713 10 return HA_EXIT_SUCCESS;
15714 }
15715
15716 43 static int rocksdb_validate_update_cf_options(
15717 THD *thd MY_ATTRIBUTE((__unused__)),
15718 struct SYS_VAR *var MY_ATTRIBUTE((__unused__)), void *save,
15719 struct st_mysql_value *value) {
15720 char buff[STRING_BUFFER_USUAL_SIZE];
15721 const char *str;
15722 int length;
15723 43 length = sizeof(buff);
15724
1/2
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
43 str = value->val_str(value, buff, &length);
15725 43 *static_cast<const char **>(save) = str;
15726
15727
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 37 times.
43 if (str == nullptr) {
15728 6 return HA_EXIT_SUCCESS;
15729 }
15730
15731
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 std::stringstream output;
15732 37 Rdb_cf_options::Name_to_config_t option_map;
15733
15734 // Basic sanity checking and parsing the options into a map. If this fails
15735 // then there's no point to proceed.
15736
4/6
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 36 times.
37 if (!Rdb_cf_options::parse_cf_options(str, &option_map, &output)) {
15737
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 my_printf_error(ER_WRONG_VALUE_FOR_VAR, "%s", MYF(0), output.str().c_str());
15738 1 return HA_EXIT_FAILURE;
15739 }
15740 // Loop through option_map and check if all specified CFs exist.
15741 36 std::vector<const std::string *> unknown_cfs;
15742
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 36 times.
71 for (const auto &option : option_map) {
15743
3/4
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 28 times.
35 if (!cf_manager.get_cf(option.first)) {
15744
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 unknown_cfs.push_back(&(option.first));
15745 }
15746 }
15747
15748
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 29 times.
36 if (!unknown_cfs.empty()) {
15749
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 std::string err(str);
15750
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 err.append(" Unknown CF: ");
15751 7 bool first = true;
15752
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 for (const auto cf : unknown_cfs) {
15753
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (first)
15754 7 first = false;
15755 else
15756 err.append(", ");
15757
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 err.append(*cf);
15758 }
15759
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "rocksdb_update_cf_options",
15760 err.c_str());
15761 7 return HA_EXIT_FAILURE;
15762 7 }
15763 29 return HA_EXIT_SUCCESS;
15764 37 }
15765
15766 35 static void rocksdb_set_update_cf_options(
15767 THD *const thd MY_ATTRIBUTE((__unused__)),
15768 struct SYS_VAR *const var MY_ATTRIBUTE((__unused__)), void *const var_ptr,
15769 const void *const save) {
15770 35 const char *const val = *static_cast<const char *const *>(save);
15771
15772
2/4
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
35 RDB_MUTEX_LOCK_CHECK(rdb_sysvars_mutex);
15773
15774
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 29 times.
35 if (!val) {
15775 6 *reinterpret_cast<char **>(var_ptr) = nullptr;
15776
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
15777 6 return;
15778 }
15779
15780
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 assert(val != nullptr);
15781
15782 // Reset the pointers regardless of how much success we had with updating
15783 // the CF options. This will results in consistent behavior and avoids
15784 // dealing with cases when only a subset of CF-s was successfully updated.
15785 29 *static_cast<const char **>(var_ptr) =
15786 29 *static_cast<const char *const *>(save);
15787
15788 // Do the real work of applying the changes.
15789 29 Rdb_cf_options::Name_to_config_t option_map;
15790
15791 // This should never fail, because of rocksdb_validate_update_cf_options
15792
3/6
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 29 times.
29 if (!Rdb_cf_options::parse_cf_options(val, &option_map)) {
15793 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
15794 return;
15795 }
15796
15797 // For each CF we have, see if we need to update any settings.
15798
3/4
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 158 times.
✓ Branch 3 taken 29 times.
187 for (const auto &cf_name : cf_manager.get_cf_names()) {
15799
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 158 times.
158 assert(!cf_name.empty());
15800
15801 std::shared_ptr<rocksdb::ColumnFamilyHandle> cfh =
15802
1/2
✓ Branch 0 taken 158 times.
✗ Branch 1 not taken.
158 cf_manager.get_cf(cf_name);
15803
15804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 158 times.
158 if (!cfh) {
15805 LogPluginErrMsg(
15806 INFORMATION_LEVEL, 0,
15807 "Skip updating options for cf %s because the cf has been dropped.",
15808 cf_name.c_str());
15809 continue;
15810 }
15811
15812
1/2
✓ Branch 0 taken 158 times.
✗ Branch 1 not taken.
158 const auto it = option_map.find(cf_name);
15813
6/10
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 131 times.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 131 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 131 times.
✓ Branch 7 taken 27 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
158 std::string per_cf_options = (it != option_map.end()) ? it->second : "";
15814
15815
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 131 times.
158 if (!per_cf_options.empty()) {
15816 27 Rdb_cf_options::Name_to_config_t opt_map;
15817
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 rocksdb::Status s = rocksdb::StringToMap(per_cf_options, &opt_map);
15818
15819
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
27 if (s != rocksdb::Status::OK()) {
15820 LogPluginErrMsg(
15821 WARNING_LEVEL, 0,
15822 "failed to convert the options for column family '%s' to a map. %s",
15823 cf_name.c_str(), s.ToString().c_str());
15824 } else {
15825
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 assert(rdb != nullptr);
15826
15827 // Finally we can apply the options.
15828 // If cf_manager.drop_cf() has been called at this point, SetOptions()
15829 // will still succeed. The options data will only be cleared when
15830 // the CF handle object is destroyed.
15831
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 s = rdb->SetOptions(cfh.get(), opt_map);
15832
15833
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
27 if (s != rocksdb::Status::OK()) {
15834 LogPluginErrMsg(
15835 WARNING_LEVEL, 0,
15836 "failed to apply the options for column family '%s'. %s",
15837 cf_name.c_str(), s.ToString().c_str());
15838 } else {
15839
9/18
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 27 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 27 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 27 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 27 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 27 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 27 times.
✗ Branch 17 not taken.
27 LogPluginErrMsg(
15840 INFORMATION_LEVEL, 0,
15841 "options for column family '%s' have been successfully updated.",
15842 cf_name.c_str());
15843
15844 // Make sure that data is internally consistent as well and update
15845 // the CF options. This is necessary also to make sure that the CF
15846 // options will be correctly reflected in the relevant table:
15847 // ROCKSDB_CF_OPTIONS in INFORMATION_SCHEMA.
15848
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 rocksdb::ColumnFamilyOptions cf_options = rdb->GetOptions(cfh.get());
15849 27 std::string updated_options;
15850
15851
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
54 s = rocksdb::GetStringFromColumnFamilyOptions(&updated_options,
15852 27 cf_options);
15853
15854
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
27 assert(s == rocksdb::Status::OK());
15855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 assert(!updated_options.empty());
15856
15857
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 cf_manager.update_options_map(cf_name, updated_options);
15858 27 }
15859 }
15860 27 }
15861
1/2
✓ Branch 0 taken 158 times.
✗ Branch 1 not taken.
187 }
15862
15863 // Our caller (`plugin_var_memalloc_global_update`) will call `my_free` to
15864 // free up resources used before.
15865
15866
2/4
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
29 RDB_MUTEX_UNLOCK_CHECK(rdb_sysvars_mutex);
15867
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 }
15868
15869 26416 void rdb_queue_save_stats_request() { rdb_bg_thread.request_save_stats(); }
15870
15871 #if defined(ROCKSDB_INCLUDE_RFR) && ROCKSDB_INCLUDE_RFR
15872 5105 void ha_rocksdb::rpl_before_delete_rows() {
15873
1/2
✓ Branch 0 taken 5105 times.
✗ Branch 1 not taken.
5105 DBUG_ENTER_FUNC();
15874
15875 5105 m_in_rpl_delete_rows = true;
15876
15877
1/2
✓ Branch 0 taken 5105 times.
✗ Branch 1 not taken.
10210 DBUG_VOID_RETURN;
15878 }
15879
15880 5105 void ha_rocksdb::rpl_after_delete_rows() {
15881
1/2
✓ Branch 0 taken 5105 times.
✗ Branch 1 not taken.
5105 DBUG_ENTER_FUNC();
15882
15883 5105 m_in_rpl_delete_rows = false;
15884
15885
1/2
✓ Branch 0 taken 5105 times.
✗ Branch 1 not taken.
10210 DBUG_VOID_RETURN;
15886 }
15887
15888 6825 void ha_rocksdb::rpl_before_update_rows() {
15889
1/2
✓ Branch 0 taken 6825 times.
✗ Branch 1 not taken.
6825 DBUG_ENTER_FUNC();
15890
15891 6825 m_in_rpl_update_rows = true;
15892
15893
1/2
✓ Branch 0 taken 6825 times.
✗ Branch 1 not taken.
13650 DBUG_VOID_RETURN;
15894 }
15895
15896 6825 void ha_rocksdb::rpl_after_update_rows() {
15897
1/2
✓ Branch 0 taken 6825 times.
✗ Branch 1 not taken.
6825 DBUG_ENTER_FUNC();
15898
15899 6825 m_in_rpl_update_rows = false;
15900
15901
1/2
✓ Branch 0 taken 6825 times.
✗ Branch 1 not taken.
13650 DBUG_VOID_RETURN;
15902 }
15903
15904 9770 bool ha_rocksdb::rpl_lookup_rows() { return !use_read_free_rpl(); }
15905
15906 117067 bool ha_rocksdb::is_read_free_rpl_table() const {
15907 #if 1 // Percona Server disabled rocksdb_read_free_rpl_tables as it's dangerous
15908 // to use
15909 117067 return true;
15910 #else
15911 return table->s && m_tbl_def->m_is_read_free_rpl_table;
15912 #endif
15913 }
15914
15915 /**
15916 @brief
15917 Read Free Replication can be used or not. Returning true means
15918 Read Free Replication can be used.
15919 */
15920 20360039 bool ha_rocksdb::use_read_free_rpl() const {
15921
1/2
✓ Branch 0 taken 20579339 times.
✗ Branch 1 not taken.
20360039 DBUG_ENTER_FUNC();
15922
15923
9/12
✓ Branch 0 taken 20590688 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117327 times.
✓ Branch 3 taken 20473361 times.
✓ Branch 4 taken 117067 times.
✓ Branch 5 taken 260 times.
✓ Branch 6 taken 117067 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 117067 times.
✓ Branch 10 taken 20436108 times.
✓ Branch 11 taken 154580 times.
20579339 if (!ha_thd()->rli_slave || table->triggers || !is_read_free_rpl_table()) {
15924
1/2
✓ Branch 0 taken 20474861 times.
✗ Branch 1 not taken.
20436108 DBUG_RETURN(false);
15925 }
15926
15927
2/4
✓ Branch 0 taken 117067 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 37513 times.
154580 switch (rocksdb_read_free_rpl) {
15928 117067 case read_free_rpl_type::OFF:
15929
1/2
✓ Branch 0 taken 117067 times.
✗ Branch 1 not taken.
117067 DBUG_RETURN(false);
15930 case read_free_rpl_type::PK_ONLY:
15931 DBUG_RETURN(!has_hidden_pk(table) && table->s->keys == 1);
15932 case read_free_rpl_type::PK_SK:
15933 DBUG_RETURN(!has_hidden_pk(table));
15934 }
15935
15936 37513 assert(false);
15937 DBUG_RETURN(false);
15938 }
15939 #endif // defined(ROCKSDB_INCLUDE_RFR) && ROCKSDB_INCLUDE_RFR
15940
15941 21292 uchar *blob_buffer::get_blob_buffer(uint current_size) {
15942 21292 auto output = m_blob_buffer_current;
15943 21292 m_blob_buffer_current = m_blob_buffer_current + current_size;
15944
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21292 times.
21292 assert((m_blob_buffer_current - m_blob_buffer_start) <=
15945 m_total_blob_buffer_allocated);
15946 21292 return output;
15947 }
15948
15949 37861 bool blob_buffer::reset_blob_buffer(uint total_size) {
15950
2/2
✓ Branch 0 taken 3682 times.
✓ Branch 1 taken 34179 times.
37861 if (m_blob_buffer_start == nullptr) {
15951 3682 m_blob_buffer_start = reinterpret_cast<uchar *>(
15952 3682 my_malloc(PSI_NOT_INSTRUMENTED, total_size, MYF(0)));
15953 3682 m_total_blob_buffer_allocated = total_size;
15954
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34179 times.
34179 } else if (m_total_blob_buffer_allocated < total_size) {
15955 my_free(m_blob_buffer_start);
15956 m_blob_buffer_start = reinterpret_cast<uchar *>(
15957 my_malloc(PSI_NOT_INSTRUMENTED, total_size, MYF(0)));
15958 m_total_blob_buffer_allocated = total_size;
15959 }
15960
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37861 times.
37861 if (!m_blob_buffer_start) return true;
15961 37861 m_blob_buffer_current = m_blob_buffer_start;
15962 37861 return false;
15963 }
15964
15965 4186484 void blob_buffer::release_blob_buffer() {
15966
2/2
✓ Branch 0 taken 3682 times.
✓ Branch 1 taken 4182802 times.
4186484 if (m_blob_buffer_start != nullptr) {
15967 3682 my_free(m_blob_buffer_start);
15968 3682 m_blob_buffer_start = nullptr;
15969 }
15970 4186484 }
15971
15972 385107 double ha_rocksdb::read_time(uint index, uint ranges, ha_rows rows) {
15973
1/2
✓ Branch 0 taken 385107 times.
✗ Branch 1 not taken.
385107 DBUG_ENTER_FUNC();
15974
15975
2/2
✓ Branch 0 taken 71136 times.
✓ Branch 1 taken 313971 times.
385107 if (index != table->s->primary_key) {
15976 /* Non covering index range scan */
15977
1/2
✓ Branch 0 taken 71136 times.
✗ Branch 1 not taken.
71136 DBUG_RETURN(handler::read_time(index, ranges, rows));
15978 }
15979
15980
1/2
✓ Branch 0 taken 313971 times.
✗ Branch 1 not taken.
313971 DBUG_RETURN((rows / 20.0) + 1);
15981 }
15982
15983 3431 void ha_rocksdb::print_error(int error, myf errflag) {
15984
3/3
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 262 times.
✓ Branch 2 taken 3105 times.
3431 switch (error) {
15985 64 case HA_ERR_ROCKSDB_STATUS_BUSY:
15986 64 handler::print_error(HA_ERR_LOCK_DEADLOCK, errflag);
15987 64 break;
15988 262 case HA_ERR_LOCK_WAIT_TIMEOUT:
15989
5/6
✓ Branch 0 taken 262 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 256 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 256 times.
262 if (error == HA_ERR_LOCK_WAIT_TIMEOUT && my_core::thd_killed(ha_thd())) {
15990 6 my_error(ER_QUERY_TIMEOUT, errflag,
15991 6 table_share->table_name.str /*, error*/);
15992 } else {
15993 256 handler::print_error(error, errflag);
15994 }
15995 262 break;
15996 3105 default:
15997 3105 handler::print_error(error, errflag);
15998 3105 break;
15999 }
16000 3431 }
16001
16002 932 std::string rdb_corruption_marker_file_name() {
16003
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 std::string ret(rocksdb_datadir);
16004
1/2
✓ Branch 0 taken 932 times.
✗ Branch 1 not taken.
932 ret.append("/ROCKSDB_CORRUPTED");
16005 932 return ret;
16006 }
16007
16008 932 rocksdb::DBOptions *get_rocksdb_db_options() {
16009 932 return rocksdb_db_options.get();
16010 }
16011
16012 7 static void rocksdb_max_compaction_history_update(
16013 my_core::THD *const /* unused */, my_core::SYS_VAR *const /* unused */,
16014 void *const var_ptr, const void *const save) {
16015
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(rdb != nullptr);
16016
16017 7 uint64_t val = *static_cast<uint64_t *>(var_ptr) =
16018 7 *static_cast<const uint64_t *>(save);
16019 7 compaction_stats.resize_history(val);
16020 7 }
16021
16022 909 void Rdb_compaction_stats::resize_history(size_t max_history_len) {
16023
1/2
✓ Branch 0 taken 909 times.
✗ Branch 1 not taken.
909 std::lock_guard<std::mutex> guard(m_mutex);
16024 909 m_max_history_len = max_history_len;
16025
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 908 times.
909 if (m_history.size() > m_max_history_len) {
16026
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 m_history.erase(m_history.begin(),
16027 2 m_history.begin() + (m_history.size() - m_max_history_len));
16028 }
16029
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 909 times.
909 assert(m_history.size() <= m_max_history_len);
16030 909 }
16031
16032 std::vector<Rdb_compaction_stats_record>
16033 Rdb_compaction_stats::get_current_stats() {
16034 std::lock_guard<std::mutex> guard(m_mutex);
16035 std::vector<Rdb_compaction_stats_record> res;
16036 res.reserve(m_tid_to_pending_compaction.size());
16037 for (const auto &tid_and_pending_compaction : m_tid_to_pending_compaction) {
16038 res.push_back(tid_and_pending_compaction.second);
16039 }
16040 return res;
16041 }
16042
16043 std::vector<Rdb_compaction_stats_record>
16044 Rdb_compaction_stats::get_recent_history() {
16045 std::lock_guard<std::mutex> guard(m_mutex);
16046 std::vector<Rdb_compaction_stats_record> res;
16047 res.reserve(m_history.size());
16048 for (const auto &record : m_history) {
16049 res.push_back(record);
16050 }
16051 return res;
16052 }
16053
16054 18641 void Rdb_compaction_stats::record_start(rocksdb::CompactionJobInfo info) {
16055
1/2
✓ Branch 0 taken 18641 times.
✗ Branch 1 not taken.
18641 std::lock_guard<std::mutex> guard(m_mutex);
16056 18641 time_t start_timestamp = time(nullptr /* tloc */);
16057
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18641 times.
18641 assert(start_timestamp != static_cast<time_t>(-1));
16058
16059
2/4
✓ Branch 0 taken 18641 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18641 times.
✗ Branch 3 not taken.
37282 m_tid_to_pending_compaction[info.thread_id] = Rdb_compaction_stats_record{
16060 start_timestamp, static_cast<time_t>(-1) /* end_timestamp */,
16061
1/2
✓ Branch 0 taken 18641 times.
✗ Branch 1 not taken.
37282 std::move(info)};
16062 18641 }
16063
16064 18338 void Rdb_compaction_stats::record_end(rocksdb::CompactionJobInfo info) {
16065
1/2
✓ Branch 0 taken 18338 times.
✗ Branch 1 not taken.
18338 std::lock_guard<std::mutex> guard(m_mutex);
16066 auto tid_to_pending_compaction_iter =
16067
1/2
✓ Branch 0 taken 18338 times.
✗ Branch 1 not taken.
18338 m_tid_to_pending_compaction.find(info.thread_id);
16068
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18338 times.
18338 assert(tid_to_pending_compaction_iter != m_tid_to_pending_compaction.end());
16069
1/2
✓ Branch 0 taken 18338 times.
✗ Branch 1 not taken.
18338 Rdb_compaction_stats_record record;
16070
1/2
✓ Branch 0 taken 18338 times.
✗ Branch 1 not taken.
18338 if (tid_to_pending_compaction_iter != m_tid_to_pending_compaction.end()) {
16071 18338 record.start_timestamp =
16072 18338 tid_to_pending_compaction_iter->second.start_timestamp;
16073
1/2
✓ Branch 0 taken 18338 times.
✗ Branch 1 not taken.
18338 m_tid_to_pending_compaction.erase(tid_to_pending_compaction_iter);
16074 } else {
16075 record.start_timestamp = static_cast<time_t>(-1);
16076 }
16077
2/2
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 18174 times.
18338 if (m_max_history_len == 0) {
16078 164 return;
16079 }
16080
2/2
✓ Branch 0 taken 9309 times.
✓ Branch 1 taken 8865 times.
18174 if (m_history.size() == m_max_history_len) {
16081 9309 m_history.pop_front();
16082 }
16083
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18174 times.
18174 assert(m_history.size() < m_max_history_len);
16084 18174 record.end_timestamp = time(nullptr /* tloc */);
16085
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18174 times.
18174 assert(record.end_timestamp != static_cast<time_t>(-1));
16086
1/2
✓ Branch 0 taken 18174 times.
✗ Branch 1 not taken.
18174 record.info = std::move(info);
16087
1/2
✓ Branch 0 taken 18174 times.
✗ Branch 1 not taken.
18174 m_history.emplace_back(std::move(record));
16088
4/4
✓ Branch 0 taken 18174 times.
✓ Branch 1 taken 164 times.
✓ Branch 2 taken 18174 times.
✓ Branch 3 taken 164 times.
18502 }
16089
16090 756 unsigned long long get_partial_index_sort_max_mem(THD *thd) {
16091 756 return THDVAR(thd, partial_index_sort_max_mem);
16092 }
16093
16094 const rocksdb::ReadOptions &rdb_tx_acquire_snapshot(Rdb_transaction *tx) {
16095 tx->acquire_snapshot(true);
16096 return tx->m_read_opts;
16097 }
16098
16099 263036 rocksdb::Iterator *rdb_tx_get_iterator(
16100 THD *thd, rocksdb::ColumnFamilyHandle *const cf, bool skip_bloom_filter,
16101 const rocksdb::Slice &eq_cond_lower_bound,
16102 const rocksdb::Slice &eq_cond_upper_bound,
16103 const rocksdb::Snapshot **snapshot, bool read_current,
16104 bool create_snapshot) {
16105
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 262898 times.
263036 if (commit_in_the_middle(thd)) {
16106
2/4
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
138 assert(snapshot && *snapshot == nullptr);
16107
1/2
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
138 if (snapshot) {
16108
1/2
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
138 *snapshot = rdb->GetSnapshot();
16109
1/2
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
138 auto read_opts = rocksdb::ReadOptions();
16110 // TODO(mung): set based on WHERE conditions
16111 138 read_opts.total_order_seek = true;
16112 138 read_opts.snapshot = *snapshot;
16113
1/2
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
138 return rdb->NewIterator(read_opts, cf);
16114 138 } else {
16115 return nullptr;
16116 }
16117 } else {
16118 262898 Rdb_transaction *tx = get_tx_from_thd(thd);
16119 262898 return tx->get_iterator(cf, skip_bloom_filter, eq_cond_lower_bound,
16120 262898 eq_cond_upper_bound, read_current, create_snapshot);
16121 }
16122 }
16123
16124 bool rdb_tx_started(Rdb_transaction *tx) { return tx->is_tx_started(); }
16125
16126 12100520 rocksdb::Status rdb_tx_get(Rdb_transaction *tx,
16127 rocksdb::ColumnFamilyHandle *const column_family,
16128 const rocksdb::Slice &key,
16129 rocksdb::PinnableSlice *const value) {
16130 12100520 return tx->get(column_family, key, value);
16131 }
16132
16133 12579318 rocksdb::Status rdb_tx_get_for_update(Rdb_transaction *tx,
16134 const Rdb_key_def &kd,
16135 const rocksdb::Slice &key,
16136 rocksdb::PinnableSlice *const value,
16137 bool exclusive, bool skip_wait) {
16138 bool do_validate =
16139 12579318 my_core::thd_tx_isolation(tx->get_thd()) > ISO_READ_COMMITTED;
16140 rocksdb::Status s =
16141 12590182 tx->get_for_update(kd, key, value, exclusive, do_validate, skip_wait);
16142
16143 #ifndef NDEBUG
16144 12639530 ++rocksdb_num_get_for_update_calls;
16145 #endif
16146 12720778 return s;
16147 }
16148
16149 564 void rdb_tx_release_lock(Rdb_transaction *tx, const Rdb_key_def &kd,
16150 const rocksdb::Slice &key, bool force) {
16151
2/4
✓ Branch 0 taken 564 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 564 times.
✗ Branch 3 not taken.
564 tx->release_lock(kd, std::string(key.data(), key.size()), force);
16152 564 }
16153
16154 437 int rdb_tx_set_status_error(Rdb_transaction *tx, const rocksdb::Status &s,
16155 const Rdb_key_def &kd,
16156 const Rdb_tbl_def *const tbl_def) {
16157 437 return tx->set_status_error(tx->get_thd(), s, kd, tbl_def);
16158 }
16159
16160 3 static bool parse_fault_injection_file_type(const std::string &type_str,
16161 rocksdb::FileType *type) {
16162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (type_str == "kWalFile") {
16163 *type = rocksdb::FileType::kWalFile;
16164 return false;
16165
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 } else if (type_str == "kTableFile") {
16166 3 *type = rocksdb::FileType::kTableFile;
16167 3 return false;
16168 } else if (type_str == "kDescriptorFile") {
16169 *type = rocksdb::FileType::kDescriptorFile;
16170 return false;
16171 }
16172 return true;
16173 }
16174
16175 3 static bool parse_fault_injection_params(
16176 bool *retryable, uint32_t *failure_ratio,
16177 std::vector<rocksdb::FileType> *types) {
16178
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 rapidjson::Document doc;
16179
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 rapidjson::ParseResult ok = doc.Parse(opt_rocksdb_fault_injection_options);
16180
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (!ok) {
16181 LogPluginErrMsg(ERROR_LEVEL, 0,
16182 "Parse error (errcode=%d offset=%lu) "
16183 "rocksdb_fault_injection_options=%s",
16184 ok.Code(), ok.Offset(),
16185 opt_rocksdb_fault_injection_options);
16186 return true;
16187 }
16188
16189
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 auto retry_it = doc.FindMember("retry");
16190
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 auto fr_it = doc.FindMember("failure_ratio");
16191
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 auto ft_it = doc.FindMember("filetypes");
16192
16193
5/10
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
6 if (retry_it == doc.MemberEnd() || fr_it == doc.MemberEnd() ||
16194
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
6 ft_it == doc.MemberEnd()) {
16195 LogPluginErrMsg(ERROR_LEVEL, 0,
16196 "rocksdb_fault_injection_options=%s schema not valid",
16197 opt_rocksdb_fault_injection_options);
16198 return true;
16199 }
16200
16201
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
6 if (!retry_it->value.IsBool() || !fr_it->value.IsInt() ||
16202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 !ft_it->value.IsArray()) {
16203 // NO_LINT_DEBUG
16204 LogPluginErrMsg(
16205 ERROR_LEVEL, 0,
16206 "rocksdb_fault_injection_options=%s schema not valid (wrong "
16207 "types)",
16208 opt_rocksdb_fault_injection_options);
16209 return true;
16210 }
16211
16212 3 *retryable = retry_it->value.GetBool();
16213 3 *failure_ratio = fr_it->value.GetInt();
16214
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for (rapidjson::SizeType i = 0; i < ft_it->value.Size(); i++) {
16215 rocksdb::FileType type;
16216
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 if (!ft_it->value[i].IsString() ||
16217
8/20
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
6 parse_fault_injection_file_type(ft_it->value[i].GetString(), &type)) {
16218 LogPluginErrMsg(ERROR_LEVEL, 0,
16219 "Wrong filetype = %s to "
16220 "rocksdb_fault_injection_options=%s",
16221 ft_it->value[i].IsString() ? ft_it->value[i].GetString()
16222 : "(wrong type)",
16223 opt_rocksdb_fault_injection_options);
16224 return true;
16225 }
16226
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 types->push_back(type);
16227 }
16228
16229 3 return false;
16230 3 }
16231
16232 } // namespace myrocks
16233
16234 /*
16235 Register the storage engine plugin outside of myrocks namespace
16236 so that mysql_declare_plugin does not get confused when it does
16237 its name generation.
16238 */
16239
16240 struct st_mysql_storage_engine rocksdb_storage_engine = {
16241 MYSQL_HANDLERTON_INTERFACE_VERSION};
16242
16243 mysql_declare_plugin(rocksdb_se){
16244 MYSQL_STORAGE_ENGINE_PLUGIN, /* Plugin Type */
16245 &rocksdb_storage_engine, /* Plugin Descriptor */
16246 "ROCKSDB", /* Plugin Name */
16247 "Monty Program Ab", /* Plugin Author */
16248 "RocksDB storage engine", /* Plugin Description */
16249 PLUGIN_LICENSE_GPL, /* Plugin Licence */
16250 myrocks::rocksdb_init_func, /* Plugin Entry Point */
16251 nullptr, /* Plugin Check Uninstall */
16252 myrocks::rocksdb_done_func, /* Plugin Deinitializer */
16253 0x0001, /* version number (0.1) */
16254 myrocks::rocksdb_status_vars, /* status variables */
16255 myrocks::rocksdb_system_variables, /* system variables */
16256 nullptr, /* config options */
16257 0, /* flags */
16258 },
16259 myrocks::rdb_i_s_cfstats, myrocks::rdb_i_s_dbstats,
16260 myrocks::rdb_i_s_perf_context, myrocks::rdb_i_s_perf_context_global,
16261 myrocks::rdb_i_s_cfoptions, myrocks::rdb_i_s_compact_stats,
16262 myrocks::rdb_i_s_active_compact_stats, myrocks::rdb_i_s_compact_history,
16263 myrocks::rdb_i_s_global_info, myrocks::rdb_i_s_ddl,
16264 myrocks::rdb_i_s_sst_props, myrocks::rdb_i_s_index_file_map,
16265 myrocks::rdb_i_s_lock_info, myrocks::rdb_i_s_trx_info,
16266 myrocks::rdb_i_s_deadlock_info mysql_declare_plugin_end;
16267